Implements anti-aliased lines (#164734)

issue: https://github.com/flutter/flutter/issues/138682
design doc:
https://docs.google.com/document/d/19I6ToHCMlSgSava-niFWzMLGJEAd-rYiBQEGOMu8IJg/edit?tab=t.0

This puts an experimental line drawing approach behind the following
flags:
  - iOS: `FLTAntialiasLines` boolean, default NO
- Android: `io.flutter.embedding.android.ImpellerAntialiasLines`
boolean, default false

Right now they just support DrawLines and don't support line caps.

A test was added that works as a playground for vulkan, opengles and
metal. Only the Metal version was turned into a golden test though here.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files
index efc4e89e..a7b219a 100644
--- a/engine/src/flutter/ci/licenses_golden/excluded_files
+++ b/engine/src/flutter/ci/licenses_golden/excluded_files
@@ -161,6 +161,7 @@
 ../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc
 ../../../flutter/impeller/entity/contents/filters/matrix_filter_contents_unittests.cc
 ../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
+../../../flutter/impeller/entity/contents/line_contents_unittests.cc
 ../../../flutter/impeller/entity/contents/test
 ../../../flutter/impeller/entity/contents/text_contents_unittests.cc
 ../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter
index f4ec6ae..000285a 100644
--- a/engine/src/flutter/ci/licenses_golden/licenses_flutter
+++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter
@@ -51252,6 +51252,8 @@
 ORIGIN: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/contents/gradient_generator.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/contents/gradient_generator.h + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/entity/contents/line_contents.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/entity/contents/line_contents.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc + ../../../flutter/LICENSE
@@ -51357,6 +51359,8 @@
 ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/entity/shaders/line.frag + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/entity/shaders/line.vert + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.frag + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE
@@ -51689,8 +51693,8 @@
 ORIGIN: ../../../flutter/impeller/renderer/snapshot.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/renderer/surface.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/renderer/surface.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.cc + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.h + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/renderer/texture_util.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/impeller/renderer/texture_util.h + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc + ../../../flutter/LICENSE
 ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.h + ../../../flutter/LICENSE
@@ -54225,6 +54229,8 @@
 FILE: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h
 FILE: ../../../flutter/impeller/entity/contents/gradient_generator.cc
 FILE: ../../../flutter/impeller/entity/contents/gradient_generator.h
+FILE: ../../../flutter/impeller/entity/contents/line_contents.cc
+FILE: ../../../flutter/impeller/entity/contents/line_contents.h
 FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc
 FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h
 FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc
@@ -54330,6 +54336,8 @@
 FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag
 FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag
 FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag
+FILE: ../../../flutter/impeller/entity/shaders/line.frag
+FILE: ../../../flutter/impeller/entity/shaders/line.vert
 FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag
 FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert
 FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert
@@ -54663,8 +54671,8 @@
 FILE: ../../../flutter/impeller/renderer/snapshot.h
 FILE: ../../../flutter/impeller/renderer/surface.cc
 FILE: ../../../flutter/impeller/renderer/surface.h
-FILE: ../../../flutter/impeller/renderer/texture_mipmap.cc
-FILE: ../../../flutter/impeller/renderer/texture_mipmap.h
+FILE: ../../../flutter/impeller/renderer/texture_util.cc
+FILE: ../../../flutter/impeller/renderer/texture_util.h
 FILE: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp
 FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc
 FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.h
diff --git a/engine/src/flutter/common/settings.h b/engine/src/flutter/common/settings.h
index f25d302..8f41eb2 100644
--- a/engine/src/flutter/common/settings.h
+++ b/engine/src/flutter/common/settings.h
@@ -231,6 +231,9 @@
   // Whether to lazily initialize impeller PSO state.
   bool impeller_enable_lazy_shader_mode = false;
 
+  // An experimental mode that antialiases lines.
+  bool impeller_antialiased_lines = false;
+
   // Log a warning during shell initialization if Impeller is not enabled.
   bool warn_on_impeller_opt_out = false;
 
diff --git a/engine/src/flutter/display_list/testing/dl_test_surface_metal.mm b/engine/src/flutter/display_list/testing/dl_test_surface_metal.mm
index fd3201c..006952d 100644
--- a/engine/src/flutter/display_list/testing/dl_test_surface_metal.mm
+++ b/engine/src/flutter/display_list/testing/dl_test_surface_metal.mm
@@ -91,7 +91,9 @@
 
 void DlMetalSurfaceProvider::InitScreenShotter() const {
   if (!snapshotter_) {
-    snapshotter_.reset(new MetalScreenshotter(/*enable_wide_gamut=*/false));
+    impeller::PlaygroundSwitches switches;
+    switches.enable_wide_gamut = false;
+    snapshotter_.reset(new MetalScreenshotter(switches));
     auto typographer = impeller::TypographerContextSkia::Make();
     aiks_context_.reset(
         new impeller::AiksContext(snapshotter_->GetPlayground().GetContext(), typographer));
diff --git a/engine/src/flutter/impeller/base/flags.h b/engine/src/flutter/impeller/base/flags.h
index 258a833..cb581c3 100644
--- a/engine/src/flutter/impeller/base/flags.h
+++ b/engine/src/flutter/impeller/base/flags.h
@@ -10,6 +10,8 @@
   /// Whether to defer PSO construction until first use. Usage Will introduce
   /// raster jank.
   bool lazy_shader_mode = false;
+  /// When turned on DrawLine will use the experimental antialiased path.
+  bool antialiased_lines = false;
 };
 }  // namespace impeller
 
diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc
index be8cb9a..0f4729c 100644
--- a/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc
+++ b/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc
@@ -382,6 +382,47 @@
   ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
 }
 
+TEST_P(AiksTest, SimpleExperimentAntialiasLines) {
+  DisplayListBuilder builder;
+  builder.Scale(GetContentScale().x, GetContentScale().y);
+
+  builder.DrawPaint(DlPaint(DlColor(0xff111111)));
+
+  DlPaint paint;
+  paint.setColor(DlColor::kGreenYellow());
+  paint.setStrokeWidth(10);
+
+  auto draw = [&builder](DlPaint& paint) {
+    for (auto cap :
+         {DlStrokeCap::kButt, DlStrokeCap::kSquare, DlStrokeCap::kRound}) {
+      paint.setStrokeCap(cap);
+      DlPoint origin = {100, 100};
+      builder.DrawLine(DlPoint(150, 100), DlPoint(250, 100), paint);
+      for (int d = 15; d < 90; d += 15) {
+        Matrix m = Matrix::MakeRotationZ(Degrees(d));
+        Point origin = {100, 100};
+        Point p0 = {50, 0};
+        Point p1 = {150, 0};
+        auto a = origin + m * p0;
+        auto b = origin + m * p1;
+
+        builder.DrawLine(a, b, paint);
+      }
+      builder.DrawLine(DlPoint(100, 150), DlPoint(100, 250), paint);
+      builder.DrawCircle(origin, 35, paint);
+
+      builder.DrawLine(DlPoint(250, 250), DlPoint(250, 250), paint);
+
+      builder.Translate(250, 0);
+    }
+    builder.Translate(-750, 250);
+  };
+
+  draw(paint);
+
+  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
 TEST_P(AiksTest, DrawRectStrokesRenderCorrectly) {
   DisplayListBuilder builder;
   DlPaint paint;
diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc
index c18ebc8..9c3380d 100644
--- a/engine/src/flutter/impeller/display_list/canvas.cc
+++ b/engine/src/flutter/impeller/display_list/canvas.cc
@@ -24,6 +24,7 @@
 #include "impeller/entity/contents/content_context.h"
 #include "impeller/entity/contents/filters/filter_contents.h"
 #include "impeller/entity/contents/framebuffer_blend_contents.h"
+#include "impeller/entity/contents/line_contents.h"
 #include "impeller/entity/contents/solid_rrect_blur_contents.h"
 #include "impeller/entity/contents/text_contents.h"
 #include "impeller/entity/contents/texture_contents.h"
@@ -459,9 +460,19 @@
   entity.SetTransform(GetCurrentTransform());
   entity.SetBlendMode(paint.blend_mode);
 
-  LineGeometry geom(p0, p1, paint.stroke_width, paint.stroke_cap);
-  AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint,
-                                          /*reuse_depth=*/reuse_depth);
+  auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.stroke_width,
+                                                 paint.stroke_cap);
+
+  if (renderer_.GetContext()->GetFlags().antialiased_lines &&
+      !paint.color_filter && !paint.invert_colors && !paint.image_filter &&
+      !paint.mask_blur_descriptor.has_value() && !paint.color_source) {
+    auto contents = LineContents::Make(std::move(geometry), paint.color);
+    entity.SetContents(std::move(contents));
+    AddRenderEntityToCurrentPass(entity, reuse_depth);
+  } else {
+    AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
+                                            /*reuse_depth=*/reuse_depth);
+  }
 }
 
 void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn
index fe25c77..688cf7a 100644
--- a/engine/src/flutter/impeller/entity/BUILD.gn
+++ b/engine/src/flutter/impeller/entity/BUILD.gn
@@ -35,6 +35,8 @@
     "shaders/gradients/radial_gradient_uniform_fill.frag",
     "shaders/gradients/sweep_gradient_fill.frag",
     "shaders/gradients/sweep_gradient_uniform_fill.frag",
+    "shaders/line.frag",
+    "shaders/line.vert",
     "shaders/rrect_blur.vert",
     "shaders/rrect_blur.frag",
     "shaders/runtime_effect.vert",
@@ -159,6 +161,8 @@
     "contents/framebuffer_blend_contents.h",
     "contents/gradient_generator.cc",
     "contents/gradient_generator.h",
+    "contents/line_contents.cc",
+    "contents/line_contents.h",
     "contents/linear_gradient_contents.cc",
     "contents/linear_gradient_contents.h",
     "contents/radial_gradient_contents.cc",
@@ -254,6 +258,7 @@
     "contents/filters/inputs/filter_input_unittests.cc",
     "contents/filters/matrix_filter_contents_unittests.cc",
     "contents/host_buffer_unittests.cc",
+    "contents/line_contents_unittests.cc",
     "contents/text_contents_unittests.cc",
     "contents/tiled_texture_contents_unittests.cc",
     "draw_order_resolver_unittests.cc",
diff --git a/engine/src/flutter/impeller/entity/contents/color_source_contents.h b/engine/src/flutter/impeller/entity/contents/color_source_contents.h
index 96bfd62..6d58ab0 100644
--- a/engine/src/flutter/impeller/entity/contents/color_source_contents.h
+++ b/engine/src/flutter/impeller/entity/contents/color_source_contents.h
@@ -36,6 +36,15 @@
 ///
 class ColorSourceContents : public Contents {
  public:
+  using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
+  using PipelineBuilderCallback =
+      std::function<PipelineRef(ContentContextOptions)>;
+  using CreateGeometryCallback =
+      std::function<GeometryResult(const ContentContext& renderer,
+                                   const Entity& entity,
+                                   RenderPass& pass,
+                                   const Geometry* geom)>;
+
   ColorSourceContents();
 
   ~ColorSourceContents() override;
@@ -99,41 +108,21 @@
   // |Contents|
   void SetInheritedOpacity(Scalar opacity) override;
 
- protected:
-  using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
-  using PipelineBuilderCallback =
-      std::function<PipelineRef(ContentContextOptions)>;
-  using CreateGeometryCallback =
-      std::function<GeometryResult(const ContentContext& renderer,
-                                   const Entity& entity,
-                                   RenderPass& pass,
-                                   const Geometry* geom)>;
-
-  static GeometryResult DefaultCreateGeometryCallback(
-      const ContentContext& renderer,
-      const Entity& entity,
-      RenderPass& pass,
-      const Geometry* geom) {
-    return geom->GetPositionBuffer(renderer, entity, pass);
-  }
-
-  /// @brief Whether the entity should be treated as non-opaque due to stroke
-  ///        geometry requiring alpha for coverage.
-  bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;
-
   template <typename VertexShaderT>
-  bool DrawGeometry(const ContentContext& renderer,
-                    const Entity& entity,
-                    RenderPass& pass,
-                    const PipelineBuilderCallback& pipeline_callback,
-                    typename VertexShaderT::FrameInfo frame_info,
-                    const BindFragmentCallback& bind_fragment_callback,
-                    bool force_stencil = false,
-                    const CreateGeometryCallback& create_geom_callback =
-                        DefaultCreateGeometryCallback) const {
+  static bool DrawGeometry(const Contents* contents,
+                           const Geometry* geometry,
+                           const ContentContext& renderer,
+                           const Entity& entity,
+                           RenderPass& pass,
+                           const PipelineBuilderCallback& pipeline_callback,
+                           typename VertexShaderT::FrameInfo frame_info,
+                           const BindFragmentCallback& bind_fragment_callback,
+                           bool force_stencil = false,
+                           const CreateGeometryCallback& create_geom_callback =
+                               DefaultCreateGeometryCallback) {
     auto options = OptionsFromPassAndEntity(pass, entity);
 
-    GeometryResult::Mode geometry_mode = GetGeometry()->GetResultMode();
+    GeometryResult::Mode geometry_mode = geometry->GetResultMode();
     bool do_cover_draw = false;
     Rect cover_area = {};
 
@@ -151,7 +140,7 @@
       /// Stencil preparation draw.
 
       GeometryResult stencil_geometry_result =
-          GetGeometry()->GetPositionBuffer(renderer, entity, pass);
+          geometry->GetPositionBuffer(renderer, entity, pass);
       if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) {
         return true;
       }
@@ -194,7 +183,7 @@
 
       options.blend_mode = entity.GetBlendMode();
       options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
-      std::optional<Rect> maybe_cover_area = GetGeometry()->GetCoverage({});
+      std::optional<Rect> maybe_cover_area = geometry->GetCoverage({});
       if (!maybe_cover_area.has_value()) {
         return true;
       }
@@ -207,8 +196,7 @@
       RectGeometry geom(cover_area);
       geometry_result = create_geom_callback(renderer, entity, pass, &geom);
     } else {
-      geometry_result =
-          create_geom_callback(renderer, entity, pass, GetGeometry());
+      geometry_result = create_geom_callback(renderer, entity, pass, geometry);
     }
 
     if (geometry_result.vertex_buffer.vertex_count == 0u) {
@@ -261,11 +249,47 @@
     if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
         options.blend_mode != BlendMode::kSrc) {
       return RenderClipRestore(renderer, pass, entity.GetClipDepth(),
-                               GetCoverage(entity));
+                               contents->GetCoverage(entity));
     }
     return true;
   }
 
+ protected:
+  static GeometryResult DefaultCreateGeometryCallback(
+      const ContentContext& renderer,
+      const Entity& entity,
+      RenderPass& pass,
+      const Geometry* geom) {
+    return geom->GetPositionBuffer(renderer, entity, pass);
+  }
+
+  /// @brief Whether the entity should be treated as non-opaque due to stroke
+  ///        geometry requiring alpha for coverage.
+  bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;
+
+  template <typename VertexShaderT>
+  bool DrawGeometry(const ContentContext& renderer,
+                    const Entity& entity,
+                    RenderPass& pass,
+                    const PipelineBuilderCallback& pipeline_callback,
+                    typename VertexShaderT::FrameInfo frame_info,
+                    const BindFragmentCallback& bind_fragment_callback,
+                    bool force_stencil = false,
+                    const CreateGeometryCallback& create_geom_callback =
+                        DefaultCreateGeometryCallback) const {
+    //
+    return DrawGeometry<VertexShaderT>(this,                    //
+                                       GetGeometry(),           //
+                                       renderer,                //
+                                       entity,                  //
+                                       pass,                    //
+                                       pipeline_callback,       //
+                                       frame_info,              //
+                                       bind_fragment_callback,  //
+                                       force_stencil,           //
+                                       create_geom_callback);
+  }
+
  private:
   const Geometry* geometry_ = nullptr;
   Matrix inverse_matrix_;
diff --git a/engine/src/flutter/impeller/entity/contents/content_context.cc b/engine/src/flutter/impeller/entity/contents/content_context.cc
index 376836f..41383a7 100644
--- a/engine/src/flutter/impeller/entity/contents/content_context.cc
+++ b/engine/src/flutter/impeller/entity/contents/content_context.cc
@@ -18,7 +18,7 @@
 #include "impeller/renderer/pipeline_descriptor.h"
 #include "impeller/renderer/pipeline_library.h"
 #include "impeller/renderer/render_target.h"
-#include "impeller/renderer/texture_mipmap.h"
+#include "impeller/renderer/texture_util.h"
 #include "impeller/tessellator/tessellator.h"
 #include "impeller/typographer/typographer_context.h"
 
@@ -329,6 +329,7 @@
     solid_fill_pipelines_.CreateDefault(*context_, options);
     texture_pipelines_.CreateDefault(*context_, options);
     fast_gradient_pipelines_.CreateDefault(*context_, options);
+    line_pipelines_.CreateDefault(*context_, options);
 
     if (context_->GetCapabilities()->SupportsSSBO()) {
       linear_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options);
@@ -1159,6 +1160,10 @@
   return GetPipeline(vertices_uber_shader_, opts);
 }
 
+PipelineRef ContentContext::GetLinePipeline(ContentContextOptions opts) const {
+  return GetPipeline(line_pipelines_, opts);
+}
+
 #ifdef IMPELLER_ENABLE_OPENGLES
 PipelineRef ContentContext::GetDownsampleTextureGlesPipeline(
     ContentContextOptions opts) const {
diff --git a/engine/src/flutter/impeller/entity/contents/content_context.h b/engine/src/flutter/impeller/entity/contents/content_context.h
index 5daf9c1..f24ae29 100644
--- a/engine/src/flutter/impeller/entity/contents/content_context.h
+++ b/engine/src/flutter/impeller/entity/contents/content_context.h
@@ -41,6 +41,8 @@
 #include "impeller/entity/glyph_atlas.frag.h"
 #include "impeller/entity/glyph_atlas.vert.h"
 #include "impeller/entity/gradient_fill.vert.h"
+#include "impeller/entity/line.frag.h"
+#include "impeller/entity/line.vert.h"
 #include "impeller/entity/linear_gradient_fill.frag.h"
 #include "impeller/entity/linear_to_srgb_filter.frag.h"
 #include "impeller/entity/morphology_filter.frag.h"
@@ -147,6 +149,7 @@
 using FramebufferBlendSoftLightPipeline = FramebufferBlendPipelineHandle;
 using GaussianBlurPipeline = RenderPipelineHandle<FilterPositionUvVertexShader, GaussianFragmentShader>;
 using GlyphAtlasPipeline = RenderPipelineHandle<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
+using LinePipeline = RenderPipelineHandle<LineVertexShader, LineFragmentShader>;
 using LinearGradientFillPipeline = GradientPipelineHandle<LinearGradientFillFragmentShader>;
 using LinearGradientSSBOFillPipeline = GradientPipelineHandle<LinearGradientSsboFillFragmentShader>;
 using LinearGradientUniformFillPipeline = GradientPipelineHandle<LinearGradientUniformFillFragmentShader>;
@@ -352,6 +355,7 @@
   PipelineRef GetFramebufferBlendSoftLightPipeline(ContentContextOptions opts) const;
   PipelineRef GetGaussianBlurPipeline(ContentContextOptions opts) const;
   PipelineRef GetGlyphAtlasPipeline(ContentContextOptions opts) const;
+  PipelineRef GetLinePipeline(ContentContextOptions opts) const;
   PipelineRef GetLinearGradientFillPipeline(ContentContextOptions opts) const;
   PipelineRef GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const;
   PipelineRef GetLinearGradientUniformFillPipeline(ContentContextOptions opts) const;
@@ -645,6 +649,7 @@
   mutable Variants<FramebufferBlendSoftLightPipeline> framebuffer_blend_softlight_pipelines_;
   mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
   mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
+  mutable Variants<LinePipeline> line_pipelines_;
   mutable Variants<LinearGradientFillPipeline> linear_gradient_fill_pipelines_;
   mutable Variants<LinearGradientSSBOFillPipeline> linear_gradient_ssbo_fill_pipelines_;
   mutable Variants<LinearGradientUniformFillPipeline> linear_gradient_uniform_fill_pipelines_;
diff --git a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc
index 440599d..f83c142 100644
--- a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc
+++ b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc
@@ -10,6 +10,7 @@
 #include "impeller/core/formats.h"
 #include "impeller/core/texture.h"
 #include "impeller/renderer/context.h"
+#include "impeller/renderer/texture_util.h"
 
 namespace impeller {
 
@@ -25,29 +26,9 @@
   texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible;
   texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
   texture_descriptor.size = {gradient_data.texture_size, 1};
-  auto texture =
-      context->GetResourceAllocator()->CreateTexture(texture_descriptor);
-  if (!texture) {
-    FML_DLOG(ERROR) << "Could not create Impeller texture.";
-    return nullptr;
-  }
 
-  auto data_mapping =
-      std::make_shared<fml::DataMapping>(gradient_data.color_bytes);
-  auto buffer =
-      context->GetResourceAllocator()->CreateBufferWithCopy(*data_mapping);
-
-  auto cmd_buffer = context->CreateCommandBuffer();
-  auto blit_pass = cmd_buffer->CreateBlitPass();
-  blit_pass->AddCopy(DeviceBuffer::AsBufferView(std::move(buffer)), texture);
-
-  if (!blit_pass->EncodeCommands() ||
-      !context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
-    return nullptr;
-  }
-
-  texture->SetLabel(impeller::SPrintF("Gradient(%p)", texture.get()).c_str());
-  return texture;
+  return CreateTexture(texture_descriptor, gradient_data.color_bytes, context,
+                       "Gradient");
 }
 
 std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
diff --git a/engine/src/flutter/impeller/entity/contents/line_contents.cc b/engine/src/flutter/impeller/entity/contents/line_contents.cc
new file mode 100644
index 0000000..165645f
--- /dev/null
+++ b/engine/src/flutter/impeller/entity/contents/line_contents.cc
@@ -0,0 +1,188 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "impeller/entity/contents/line_contents.h"
+#include "impeller/entity/contents/clip_contents.h"
+#include "impeller/entity/contents/color_source_contents.h"
+#include "impeller/entity/geometry/rect_geometry.h"
+#include "impeller/renderer/texture_util.h"
+
+namespace impeller {
+
+using VS = LinePipeline::VertexShader;
+using FS = LinePipeline::FragmentShader;
+
+namespace {
+using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
+using PipelineBuilderCallback =
+    std::function<PipelineRef(ContentContextOptions)>;
+using CreateGeometryCallback =
+    std::function<GeometryResult(const ContentContext& renderer,
+                                 const Entity& entity,
+                                 RenderPass& pass,
+                                 const Geometry* geometry)>;
+
+const int32_t kCurveResolution = 32;
+const Scalar kSampleRadius = 0.5f;
+
+struct LineInfo {
+  Vector3 e0;
+  Vector3 e1;
+  Vector3 e2;
+  Vector3 e3;
+};
+
+LineInfo CalculateLineInfo(Point p0, Point p1, Scalar width, Scalar radius) {
+  Vector2 diff = p0 - p1;
+  float k = 2.0 / ((2.0 * radius + width) * sqrt(diff.Dot(diff)));
+
+  return LineInfo{
+      .e0 = Vector3(k * (p0.y - p1.y),  //
+                    k * (p1.x - p0.x),  //
+                    1.0 + k * (p0.x * p1.y - p1.x * p0.y)),
+      .e1 = Vector3(
+          k * (p1.x - p0.x),  //
+          k * (p1.y - p0.y),  //
+          1.0 + k * (p0.x * p0.x + p0.y * p0.y - p0.x * p1.x - p0.y * p1.y)),
+      .e2 = Vector3(k * (p1.y - p0.y),  //
+                    k * (p0.x - p1.x),  //
+                    1.0 + k * (p1.x * p0.y - p0.x * p1.y)),
+      .e3 = Vector3(
+          k * (p0.x - p1.x),  //
+          k * (p0.y - p1.y),  //
+          1.0 + k * (p1.x * p1.x + p1.y * p1.y - p0.x * p1.x - p0.y * p1.y)),
+  };
+}
+
+uint8_t DoubleToUint8(double x) {
+  return static_cast<uint8_t>(std::clamp(std::round(x * 255.0), 0.0, 255.0));
+}
+
+/// See also: CreateGradientTexture
+std::shared_ptr<Texture> CreateCurveTexture(
+    Scalar width,
+    const std::shared_ptr<impeller::Context>& context) {
+  //
+  impeller::TextureDescriptor texture_descriptor;
+  texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible;
+  texture_descriptor.format = PixelFormat::kR8UNormInt;
+  texture_descriptor.size = {kCurveResolution, 1};
+
+  std::vector<uint8_t> curve_data;
+  curve_data.reserve(kCurveResolution);
+  for (int i = 0; i < kCurveResolution; ++i) {
+    double norm = (static_cast<double>(i) + 1.0) / 32.0;
+    double loc = norm * (kSampleRadius + width / 2.0);
+    double den = kSampleRadius * 2.0 + 1.0;
+    curve_data.push_back(DoubleToUint8(loc / den));
+  }
+
+  return CreateTexture(texture_descriptor, curve_data, context, "LineCurve");
+}
+
+GeometryResult CreateGeometry(const ContentContext& renderer,
+                              const Entity& entity,
+                              RenderPass& pass,
+                              const Geometry* geometry) {
+  using PerVertexData = LineVertexShader::PerVertexData;
+  const LineGeometry* line_geometry =
+      static_cast<const LineGeometry*>(geometry);
+
+  auto& transform = entity.GetTransform();
+
+  Point corners[4];
+  if (!LineGeometry::ComputeCorners(
+          corners, transform,
+          /*extend_endpoints=*/line_geometry->GetCap() != Cap::kButt,
+          line_geometry->GetP0(), line_geometry->GetP1(),
+          line_geometry->GetWidth() + kSampleRadius)) {
+    return kEmptyResult;
+  }
+
+  auto& host_buffer = renderer.GetTransientsBuffer();
+
+  size_t count = 4;
+  LineInfo line_info =
+      CalculateLineInfo(line_geometry->GetP0(), line_geometry->GetP1(),
+                        line_geometry->GetWidth(), kSampleRadius);
+  BufferView vertex_buffer = host_buffer.Emplace(
+      count * sizeof(PerVertexData), alignof(PerVertexData),
+      [&corners, &line_info](uint8_t* buffer) {
+        auto vertices = reinterpret_cast<PerVertexData*>(buffer);
+        for (auto& corner : corners) {
+          *vertices++ = {
+              .position = corner,
+              .e0 = line_info.e0,
+              .e1 = line_info.e1,
+              .e2 = line_info.e2,
+              .e3 = line_info.e3,
+          };
+        }
+      });
+
+  std::shared_ptr<Texture> curve_texture =
+      CreateCurveTexture(line_geometry->GetWidth(), renderer.GetContext());
+
+  SamplerDescriptor sampler_desc;
+  sampler_desc.min_filter = MinMagFilter::kLinear;
+  sampler_desc.mag_filter = MinMagFilter::kLinear;
+
+  FS::BindCurve(
+      pass, curve_texture,
+      renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc));
+
+  return GeometryResult{
+      .type = PrimitiveType::kTriangleStrip,
+      .vertex_buffer =
+          {
+              .vertex_buffer = vertex_buffer,
+              .vertex_count = count,
+              .index_type = IndexType::kNone,
+          },
+      .transform = entity.GetShaderTransform(pass),
+  };
+}
+}  // namespace
+
+std::unique_ptr<LineContents> LineContents::Make(
+    std::unique_ptr<LineGeometry> geometry,
+    Color color) {
+  return std::unique_ptr<LineContents>(
+      new LineContents(std::move(geometry), color));
+}
+
+LineContents::LineContents(std::unique_ptr<LineGeometry> geometry, Color color)
+    : geometry_(std::move(geometry)), color_(color) {}
+
+bool LineContents::Render(const ContentContext& renderer,
+                          const Entity& entity,
+                          RenderPass& pass) const {
+  auto& host_buffer = renderer.GetTransientsBuffer();
+
+  VS::FrameInfo frame_info;
+  FS::FragInfo frag_info;
+  frag_info.color = color_.Premultiply();
+
+  PipelineBuilderCallback pipeline_callback =
+      [&renderer](ContentContextOptions options) {
+        return renderer.GetLinePipeline(options);
+      };
+  return ColorSourceContents::DrawGeometry<VS>(
+      this, geometry_.get(), renderer, entity, pass, pipeline_callback,
+      frame_info,
+      /*bind_fragment_callback=*/
+      [&frag_info, &host_buffer](RenderPass& pass) {
+        FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
+        pass.SetCommandLabel("Line");
+        return true;
+      },
+      /*force_stencil=*/false,
+      /*create_geom_callback=*/CreateGeometry);
+}
+
+std::optional<Rect> LineContents::GetCoverage(const Entity& entity) const {
+  return geometry_->GetCoverage(entity.GetTransform());
+}
+
+}  // namespace impeller
diff --git a/engine/src/flutter/impeller/entity/contents/line_contents.h b/engine/src/flutter/impeller/entity/contents/line_contents.h
new file mode 100644
index 0000000..a04ff0b
--- /dev/null
+++ b/engine/src/flutter/impeller/entity/contents/line_contents.h
@@ -0,0 +1,34 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
+#define FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
+
+#include <memory>
+
+#include "flutter/impeller/entity/contents/contents.h"
+#include "flutter/impeller/entity/geometry/line_geometry.h"
+
+namespace impeller {
+class LineContents : public Contents {
+ public:
+  static std::unique_ptr<LineContents> Make(
+      std::unique_ptr<LineGeometry> geometry,
+      Color color);
+
+  bool Render(const ContentContext& renderer,
+              const Entity& entity,
+              RenderPass& pass) const override;
+
+  std::optional<Rect> GetCoverage(const Entity& entity) const override;
+
+ private:
+  explicit LineContents(std::unique_ptr<LineGeometry> geometry, Color color);
+
+  std::unique_ptr<LineGeometry> geometry_;
+  Color color_;
+};
+}  // namespace impeller
+
+#endif  // FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
diff --git a/engine/src/flutter/impeller/entity/contents/line_contents_unittests.cc b/engine/src/flutter/impeller/entity/contents/line_contents_unittests.cc
new file mode 100644
index 0000000..d20b20f
--- /dev/null
+++ b/engine/src/flutter/impeller/entity/contents/line_contents_unittests.cc
@@ -0,0 +1,33 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "impeller/entity/contents/line_contents.h"
+#include "third_party/googletest/googletest/include/gtest/gtest.h"
+
+namespace impeller {
+namespace testing {
+
+TEST(LineContents, Create) {
+  Path path;
+  Scalar width = 5.0f;
+  auto geometry = std::make_unique<LineGeometry>(
+      /*p0=*/Point{0, 0},      //
+      /*p1=*/Point{100, 100},  //
+      /*width=*/width,         //
+      /*cap=*/Cap::kSquare);
+  std::unique_ptr<LineContents> contents =
+      LineContents::Make(std::move(geometry), Color(1.f, 0.f, 0.f, 1.f));
+  EXPECT_TRUE(contents);
+  Entity entity;
+  std::optional<Rect> coverage = contents->GetCoverage(entity);
+  EXPECT_TRUE(coverage.has_value());
+  if (coverage.has_value()) {
+    Scalar lip = sqrt((width * width) / 2.f);
+    EXPECT_EQ(*coverage,
+              Rect::MakeXYWH(-lip, -lip, 100 + 2 * lip, 100 + 2 * lip));
+  }
+}
+
+}  // namespace testing
+}  // namespace impeller
diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.h b/engine/src/flutter/impeller/entity/geometry/geometry.h
index 257c44d..27a1445 100644
--- a/engine/src/flutter/impeller/entity/geometry/geometry.h
+++ b/engine/src/flutter/impeller/entity/geometry/geometry.h
@@ -119,7 +119,6 @@
     return 1.0;
   }
 
- protected:
   static GeometryResult ComputePositionGeometry(
       const ContentContext& renderer,
       const Tessellator::VertexGenerator& generator,
diff --git a/engine/src/flutter/impeller/entity/geometry/line_geometry.cc b/engine/src/flutter/impeller/entity/geometry/line_geometry.cc
index 56508b0..4a58578 100644
--- a/engine/src/flutter/impeller/entity/geometry/line_geometry.cc
+++ b/engine/src/flutter/impeller/entity/geometry/line_geometry.cc
@@ -26,13 +26,16 @@
 }
 
 Vector2 LineGeometry::ComputeAlongVector(const Matrix& transform,
-                                         bool allow_zero_length) const {
-  Scalar stroke_half_width = ComputePixelHalfWidth(transform, width_);
+                                         bool allow_zero_length,
+                                         Point p0,
+                                         Point p1,
+                                         Scalar width) {
+  Scalar stroke_half_width = ComputePixelHalfWidth(transform, width);
   if (stroke_half_width < kEhCloseEnough) {
     return {};
   }
 
-  auto along = p1_ - p0_;
+  auto along = p1 - p0;
   Scalar length = along.GetLength();
   if (length < kEhCloseEnough) {
     if (!allow_zero_length) {
@@ -47,17 +50,20 @@
 
 bool LineGeometry::ComputeCorners(Point corners[4],
                                   const Matrix& transform,
-                                  bool extend_endpoints) const {
-  auto along = ComputeAlongVector(transform, extend_endpoints);
+                                  bool extend_endpoints,
+                                  Point p0,
+                                  Point p1,
+                                  Scalar width) {
+  auto along = ComputeAlongVector(transform, extend_endpoints, p0, p1, width);
   if (along.IsZero()) {
     return false;
   }
 
   auto across = Vector2(along.y, -along.x);
-  corners[0] = p0_ - across;
-  corners[1] = p1_ - across;
-  corners[2] = p0_ + across;
-  corners[3] = p1_ + across;
+  corners[0] = p0 - across;
+  corners[1] = p1 - across;
+  corners[2] = p0 + across;
+  corners[3] = p1 + across;
   if (extend_endpoints) {
     corners[0] -= along;
     corners[1] += along;
@@ -86,7 +92,8 @@
   }
 
   Point corners[4];
-  if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare)) {
+  if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare, p0_, p1_,
+                      width_)) {
     return kEmptyResult;
   }
 
@@ -118,7 +125,8 @@
 std::optional<Rect> LineGeometry::GetCoverage(const Matrix& transform) const {
   Point corners[4];
   // Note: MSAA boolean doesn't matter for coverage computation.
-  if (!ComputeCorners(corners, transform, cap_ != Cap::kButt)) {
+  if (!ComputeCorners(corners, transform, cap_ != Cap::kButt, p0_, p1_,
+                      width_)) {
     return {};
   }
 
diff --git a/engine/src/flutter/impeller/entity/geometry/line_geometry.h b/engine/src/flutter/impeller/entity/geometry/line_geometry.h
index 340d324..3eac8e9 100644
--- a/engine/src/flutter/impeller/entity/geometry/line_geometry.h
+++ b/engine/src/flutter/impeller/entity/geometry/line_geometry.h
@@ -25,7 +25,20 @@
 
   Scalar ComputeAlphaCoverage(const Matrix& transform) const override;
 
- private:
+  // |Geometry|
+  std::optional<Rect> GetCoverage(const Matrix& transform) const override;
+
+  Point GetP0() const { return p0_; }
+  Point GetP1() const { return p1_; }
+  Scalar GetWidth() const { return width_; }
+  Cap GetCap() const { return cap_; }
+
+  static Vector2 ComputeAlongVector(const Matrix& transform,
+                                    bool allow_zero_length,
+                                    Point p0,
+                                    Point p1,
+                                    Scalar width);
+
   // Computes the 4 corners of a rectangle that defines the line and
   // possibly extended endpoints which will be rendered under the given
   // transform, and returns true if such a rectangle is defined.
@@ -40,21 +53,19 @@
   // if the calling code is planning to draw the round caps on the ends.
   //
   // @return true if the transform and width were not degenerate
-  bool ComputeCorners(Point corners[4],
-                      const Matrix& transform,
-                      bool extend_endpoints) const;
+  static bool ComputeCorners(Point corners[4],
+                             const Matrix& transform,
+                             bool extend_endpoints,
+                             Point p0,
+                             Point p1,
+                             Scalar width);
 
-  Vector2 ComputeAlongVector(const Matrix& transform,
-                             bool allow_zero_length) const;
-
+ private:
   // |Geometry|
   GeometryResult GetPositionBuffer(const ContentContext& renderer,
                                    const Entity& entity,
                                    RenderPass& pass) const override;
 
-  // |Geometry|
-  std::optional<Rect> GetCoverage(const Matrix& transform) const override;
-
   Point p0_;
   Point p1_;
   Scalar width_;
diff --git a/engine/src/flutter/impeller/entity/inline_pass_context.cc b/engine/src/flutter/impeller/entity/inline_pass_context.cc
index e8ea948..31bb6b3 100644
--- a/engine/src/flutter/impeller/entity/inline_pass_context.cc
+++ b/engine/src/flutter/impeller/entity/inline_pass_context.cc
@@ -13,7 +13,7 @@
 #include "impeller/entity/entity_pass_target.h"
 #include "impeller/renderer/command_buffer.h"
 #include "impeller/renderer/render_pass.h"
-#include "impeller/renderer/texture_mipmap.h"
+#include "impeller/renderer/texture_util.h"
 
 namespace impeller {
 
diff --git a/engine/src/flutter/impeller/entity/shaders/line.frag b/engine/src/flutter/impeller/entity/shaders/line.frag
new file mode 100644
index 0000000..32455a7
--- /dev/null
+++ b/engine/src/flutter/impeller/entity/shaders/line.frag
@@ -0,0 +1,44 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+precision mediump float;
+
+#include <impeller/types.glsl>
+
+uniform FragInfo {
+  vec4 color;
+}
+frag_info;
+
+uniform sampler2D curve;
+
+highp in vec2 v_position;
+// These should be `flat` but that doesn't work in our glsl compiler. It
+// shouldn't make any visual difference.
+highp in vec3 v_e0;
+highp in vec3 v_e1;
+highp in vec3 v_e2;
+highp in vec3 v_e3;
+
+out vec4 frag_color;
+
+float lookup(float x) {
+  return texture(curve, vec2(x, 0)).r;
+}
+
+float CalculateLine() {
+  vec3 pos = vec3(v_position.xy, 1.0);
+  vec4 d = vec4(dot(pos, v_e0), dot(pos, v_e1), dot(pos, v_e2), dot(pos, v_e3));
+
+  if (any(lessThan(d, vec4(0.0)))) {
+    return 0.0;
+  }
+
+  return lookup(min(d.x, d.z)) * lookup(min(d.y, d.w));
+}
+
+void main() {
+  float line = CalculateLine();
+  frag_color = vec4(frag_info.color.xyz, line);
+}
diff --git a/engine/src/flutter/impeller/entity/shaders/line.vert b/engine/src/flutter/impeller/entity/shaders/line.vert
new file mode 100644
index 0000000..938bfdc
--- /dev/null
+++ b/engine/src/flutter/impeller/entity/shaders/line.vert
@@ -0,0 +1,32 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <impeller/types.glsl>
+
+uniform FrameInfo {
+  mat4 mvp;
+}
+frame_info;
+
+in vec2 position;
+
+in vec3 e0;
+in vec3 e1;
+in vec3 e2;
+in vec3 e3;
+
+out vec2 v_position;
+out vec3 v_e0;
+out vec3 v_e1;
+out vec3 v_e2;
+out vec3 v_e3;
+
+void main() {
+  gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0);
+  v_position = position;
+  v_e0 = e0;
+  v_e1 = e1;
+  v_e2 = e2;
+  v_e3 = e3;
+}
diff --git a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc
index 6acc5d7..12b5103 100644
--- a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc
+++ b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc
@@ -155,7 +155,11 @@
   setenv("VK_ICD_FILENAMES", icd_path.c_str(), 1);
 
   std::string test_name = GetTestName();
-  bool enable_wide_gamut = test_name.find("WideGamut_") != std::string::npos;
+  PlaygroundSwitches switches;
+  switches.enable_wide_gamut =
+      test_name.find("WideGamut_") != std::string::npos;
+  switches.flags.antialiased_lines =
+      test_name.find("ExperimentAntialiasLines_") != std::string::npos;
   switch (GetParam()) {
     case PlaygroundBackend::kMetal:
       if (!DoesSupportWideGamutTests()) {
@@ -163,12 +167,16 @@
             << "This metal device doesn't support wide gamut golden tests.";
       }
       pimpl_->screenshotter =
-          std::make_unique<testing::MetalScreenshotter>(enable_wide_gamut);
+          std::make_unique<testing::MetalScreenshotter>(switches);
       break;
     case PlaygroundBackend::kVulkan: {
-      if (enable_wide_gamut) {
+      if (switches.enable_wide_gamut) {
         GTEST_SKIP() << "Vulkan doesn't support wide gamut golden tests.";
       }
+      if (switches.flags.antialiased_lines) {
+        GTEST_SKIP()
+            << "Vulkan doesn't support antialiased lines golden tests.";
+      }
       const std::unique_ptr<PlaygroundImpl>& playground =
           GetSharedVulkanPlayground(/*enable_validations=*/true);
       pimpl_->screenshotter =
@@ -176,9 +184,13 @@
       break;
     }
     case PlaygroundBackend::kOpenGLES: {
-      if (enable_wide_gamut) {
+      if (switches.enable_wide_gamut) {
         GTEST_SKIP() << "OpenGLES doesn't support wide gamut golden tests.";
       }
+      if (switches.flags.antialiased_lines) {
+        GTEST_SKIP()
+            << "OpenGLES doesn't support antialiased lines golden tests.";
+      }
       FML_CHECK(::glfwInit() == GLFW_TRUE);
       PlaygroundSwitches playground_switches;
       playground_switches.use_angle = true;
diff --git a/engine/src/flutter/impeller/golden_tests/golden_tests.cc b/engine/src/flutter/impeller/golden_tests/golden_tests.cc
index 12b5250..d345611 100644
--- a/engine/src/flutter/impeller/golden_tests/golden_tests.cc
+++ b/engine/src/flutter/impeller/golden_tests/golden_tests.cc
@@ -49,12 +49,17 @@
       WorkingDirectory::Instance()->GetFilenamePath(filename));
 }
 
+PlaygroundSwitches GetPlaygroundSwitches() {
+  PlaygroundSwitches switches;
+  switches.enable_wide_gamut = false;
+  return switches;
+}
 }  // namespace
 
 class GoldenTests : public ::testing::Test {
  public:
   GoldenTests()
-      : screenshotter_(new MetalScreenshotter(/*enable_wide_gamut=*/false)) {}
+      : screenshotter_(new MetalScreenshotter(GetPlaygroundSwitches())) {}
 
   MetalScreenshotter& Screenshotter() { return *screenshotter_; }
 
diff --git a/engine/src/flutter/impeller/golden_tests/metal_screenshotter.h b/engine/src/flutter/impeller/golden_tests/metal_screenshotter.h
index 5b3f7f3..30cf3d4 100644
--- a/engine/src/flutter/impeller/golden_tests/metal_screenshotter.h
+++ b/engine/src/flutter/impeller/golden_tests/metal_screenshotter.h
@@ -17,7 +17,7 @@
 /// playground backend.
 class MetalScreenshotter : public Screenshotter {
  public:
-  explicit MetalScreenshotter(bool enable_wide_gamut);
+  explicit MetalScreenshotter(const PlaygroundSwitches& switches);
 
   std::unique_ptr<Screenshot> MakeScreenshot(
       AiksContext& aiks_context,
diff --git a/engine/src/flutter/impeller/golden_tests/metal_screenshotter.mm b/engine/src/flutter/impeller/golden_tests/metal_screenshotter.mm
index 5c2877f..051347d 100644
--- a/engine/src/flutter/impeller/golden_tests/metal_screenshotter.mm
+++ b/engine/src/flutter/impeller/golden_tests/metal_screenshotter.mm
@@ -13,10 +13,8 @@
 namespace impeller {
 namespace testing {
 
-MetalScreenshotter::MetalScreenshotter(bool enable_wide_gamut) {
+MetalScreenshotter::MetalScreenshotter(const PlaygroundSwitches& switches) {
   FML_CHECK(::glfwInit() == GLFW_TRUE);
-  PlaygroundSwitches switches;
-  switches.enable_wide_gamut = enable_wide_gamut;
   playground_ = PlaygroundImpl::Create(PlaygroundBackend::kMetal, switches);
 }
 
diff --git a/engine/src/flutter/impeller/playground/backend/gles/playground_impl_gles.cc b/engine/src/flutter/impeller/playground/backend/gles/playground_impl_gles.cc
index e5d446b..092a07c 100644
--- a/engine/src/flutter/impeller/playground/backend/gles/playground_impl_gles.cc
+++ b/engine/src/flutter/impeller/playground/backend/gles/playground_impl_gles.cc
@@ -133,8 +133,9 @@
     return nullptr;
   }
 
-  auto context = ContextGLES::Create(
-      Flags{}, std::move(gl), ShaderLibraryMappingsForPlayground(), true);
+  auto context =
+      ContextGLES::Create(switches_.flags, std::move(gl),
+                          ShaderLibraryMappingsForPlayground(), true);
   if (!context) {
     FML_LOG(ERROR) << "Could not create context.";
     return nullptr;
diff --git a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm
index 7d00c4a..978f01a 100644
--- a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm
+++ b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm
@@ -77,7 +77,7 @@
   }
 
   auto context = ContextMTL::Create(
-      impeller::Flags{}, ShaderLibraryMappingsForPlayground(),
+      switches.flags, ShaderLibraryMappingsForPlayground(),
       is_gpu_disabled_sync_switch_, "Playground Library",
       switches.enable_wide_gamut
           ? std::optional<PixelFormat>(PixelFormat::kB10G10R10A10XR)
diff --git a/engine/src/flutter/impeller/playground/backend/vulkan/playground_impl_vk.cc b/engine/src/flutter/impeller/playground/backend/vulkan/playground_impl_vk.cc
index 57ae5be..3ea803d 100644
--- a/engine/src/flutter/impeller/playground/backend/vulkan/playground_impl_vk.cc
+++ b/engine/src/flutter/impeller/playground/backend/vulkan/playground_impl_vk.cc
@@ -95,8 +95,9 @@
   context_settings.enable_validation = switches_.enable_vulkan_validation;
   context_settings.fatal_missing_validations =
       switches_.enable_vulkan_validation;
+  context_settings.flags = switches_.flags;
 
-  auto context_vk = ContextVK::Create(Flags{}, std::move(context_settings));
+  auto context_vk = ContextVK::Create(std::move(context_settings));
   if (!context_vk || !context_vk->IsValid()) {
     VALIDATION_LOG << "Could not create Vulkan context in the playground.";
     return;
diff --git a/engine/src/flutter/impeller/playground/playground_test.cc b/engine/src/flutter/impeller/playground/playground_test.cc
index 2e51363..e6f9f49 100644
--- a/engine/src/flutter/impeller/playground/playground_test.cc
+++ b/engine/src/flutter/impeller/playground/playground_test.cc
@@ -65,6 +65,9 @@
     return;
   }
 
+  switches.flags.antialiased_lines =
+      test_name.find("ExperimentAntialiasLines/") != std::string::npos;
+
   SetupContext(GetParam(), switches);
   SetupWindow();
 }
diff --git a/engine/src/flutter/impeller/playground/switches.h b/engine/src/flutter/impeller/playground/switches.h
index 460bd8b..29f2684 100644
--- a/engine/src/flutter/impeller/playground/switches.h
+++ b/engine/src/flutter/impeller/playground/switches.h
@@ -9,6 +9,7 @@
 #include <optional>
 
 #include "flutter/fml/command_line.h"
+#include "impeller/base/flags.h"
 
 namespace impeller {
 
@@ -34,6 +35,8 @@
 
   bool enable_wide_gamut = false;
 
+  Flags flags;
+
   PlaygroundSwitches();
 
   explicit PlaygroundSwitches(const fml::CommandLine& args);
diff --git a/engine/src/flutter/impeller/renderer/BUILD.gn b/engine/src/flutter/impeller/renderer/BUILD.gn
index fdc2ae7..5fdc59a 100644
--- a/engine/src/flutter/impeller/renderer/BUILD.gn
+++ b/engine/src/flutter/impeller/renderer/BUILD.gn
@@ -73,8 +73,8 @@
     "snapshot.h",
     "surface.cc",
     "surface.h",
-    "texture_mipmap.cc",
-    "texture_mipmap.h",
+    "texture_util.cc",
+    "texture_util.h",
     "vertex_buffer_builder.cc",
     "vertex_buffer_builder.h",
     "vertex_descriptor.cc",
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk_unittests.cc
index fe1ff03..4e40da0 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk_unittests.cc
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk_unittests.cc
@@ -34,7 +34,7 @@
   settings.enable_gpu_tracing = false;
   settings.enable_surface_control = false;
 
-  return ContextVK::Create(impeller::Flags{}, std::move(settings));
+  return ContextVK::Create(std::move(settings));
 }
 
 TEST(AndroidVulkanTest, CanImportRGBA) {
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc
index 9956c84..5b8400d 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc
@@ -102,9 +102,8 @@
   return std::nullopt;
 }
 
-std::shared_ptr<ContextVK> ContextVK::Create(const Flags& flags,
-                                             Settings settings) {
-  auto context = std::shared_ptr<ContextVK>(new ContextVK(flags));
+std::shared_ptr<ContextVK> ContextVK::Create(Settings settings) {
+  auto context = std::shared_ptr<ContextVK>(new ContextVK(settings.flags));
   context->Setup(std::move(settings));
   if (!context->IsValid()) {
     return nullptr;
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h
index 8660763..39dae91 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h
@@ -85,6 +85,7 @@
     bool enable_surface_control = false;
     /// If validations are requested but cannot be enabled, log a fatal error.
     bool fatal_missing_validations = false;
+    Flags flags;
 
     std::optional<EmbedderData> embedder_data;
 
@@ -98,8 +99,7 @@
   /// Visible for testing.
   static size_t ChooseThreadCountForWorkers(size_t hardware_concurrency);
 
-  static std::shared_ptr<ContextVK> Create(const Flags& flags,
-                                           Settings settings);
+  static std::shared_ptr<ContextVK> Create(Settings settings);
 
   uint64_t GetHash() const { return hash_; }
 
diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc
index c3a3540..0ea8bea 100644
--- a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc
+++ b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc
@@ -955,8 +955,7 @@
   g_format_properties_callback = format_properties_callback_;
   g_physical_device_properties_callback = physical_properties_callback_;
   settings.embedder_data = embedder_data_;
-  std::shared_ptr<ContextVK> result =
-      ContextVK::Create(Flags{}, std::move(settings));
+  std::shared_ptr<ContextVK> result = ContextVK::Create(std::move(settings));
   return result;
 }
 
diff --git a/engine/src/flutter/impeller/renderer/texture_mipmap.cc b/engine/src/flutter/impeller/renderer/texture_mipmap.cc
deleted file mode 100644
index 0c332ed..0000000
--- a/engine/src/flutter/impeller/renderer/texture_mipmap.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "impeller/renderer/texture_mipmap.h"
-#include "impeller/renderer/blit_pass.h"
-#include "impeller/renderer/command_buffer.h"
-
-namespace impeller {
-
-fml::Status AddMipmapGeneration(
-    const std::shared_ptr<CommandBuffer>& command_buffer,
-    const std::shared_ptr<Context>& context,
-    const std::shared_ptr<Texture>& texture) {
-  std::shared_ptr<BlitPass> blit_pass = command_buffer->CreateBlitPass();
-  bool success = blit_pass->GenerateMipmap(texture);
-  if (!success) {
-    return fml::Status(fml::StatusCode::kUnknown, "");
-  }
-  success = blit_pass->EncodeCommands();
-  if (!success) {
-    return fml::Status(fml::StatusCode::kUnknown, "");
-  }
-  return fml::Status();
-}
-
-}  // namespace impeller
diff --git a/engine/src/flutter/impeller/renderer/texture_util.cc b/engine/src/flutter/impeller/renderer/texture_util.cc
new file mode 100644
index 0000000..b50f6f0
--- /dev/null
+++ b/engine/src/flutter/impeller/renderer/texture_util.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "impeller/renderer/texture_util.h"
+#include "impeller/renderer/blit_pass.h"
+#include "impeller/renderer/command_buffer.h"
+
+namespace impeller {
+
+std::shared_ptr<Texture> CreateTexture(
+    const TextureDescriptor& texture_descriptor,
+    const std::vector<uint8_t>& data,
+    const std::shared_ptr<impeller::Context>& context,
+    std::string_view debug_label) {
+  std::shared_ptr<Texture> texture =
+      context->GetResourceAllocator()->CreateTexture(texture_descriptor);
+
+  auto data_mapping =
+      std::make_shared<fml::NonOwnedMapping>(data.data(), data.size());
+  std::shared_ptr<DeviceBuffer> buffer =
+      context->GetResourceAllocator()->CreateBufferWithCopy(*data_mapping);
+
+  std::shared_ptr<CommandBuffer> cmd_buffer = context->CreateCommandBuffer();
+  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
+  blit_pass->AddCopy(DeviceBuffer::AsBufferView(std::move(buffer)), texture);
+
+  if (!blit_pass->EncodeCommands() ||
+      !context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
+    return nullptr;
+  }
+
+  texture->SetLabel(debug_label);
+  return texture;
+}
+
+fml::Status AddMipmapGeneration(
+    const std::shared_ptr<CommandBuffer>& command_buffer,
+    const std::shared_ptr<Context>& context,
+    const std::shared_ptr<Texture>& texture) {
+  std::shared_ptr<BlitPass> blit_pass = command_buffer->CreateBlitPass();
+  bool success = blit_pass->GenerateMipmap(texture);
+  if (!success) {
+    return fml::Status(fml::StatusCode::kUnknown, "");
+  }
+  success = blit_pass->EncodeCommands();
+  if (!success) {
+    return fml::Status(fml::StatusCode::kUnknown, "");
+  }
+  return fml::Status();
+}
+
+}  // namespace impeller
diff --git a/engine/src/flutter/impeller/renderer/texture_mipmap.h b/engine/src/flutter/impeller/renderer/texture_util.h
similarity index 62%
rename from engine/src/flutter/impeller/renderer/texture_mipmap.h
rename to engine/src/flutter/impeller/renderer/texture_util.h
index a968c23..df4fd16 100644
--- a/engine/src/flutter/impeller/renderer/texture_mipmap.h
+++ b/engine/src/flutter/impeller/renderer/texture_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
-#define FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
+#ifndef FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
+#define FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
 
 #include "flutter/fml/status.h"
 #include "impeller/core/texture.h"
@@ -12,6 +12,12 @@
 
 namespace impeller {
 
+std::shared_ptr<Texture> CreateTexture(
+    const TextureDescriptor& texture_descriptor,
+    const std::vector<uint8_t>& data,
+    const std::shared_ptr<impeller::Context>& context,
+    std::string_view debug_label);
+
 /// Adds a blit command to the render pass.
 [[nodiscard]] fml::Status AddMipmapGeneration(
     const std::shared_ptr<CommandBuffer>& command_buffer,
@@ -20,4 +26,4 @@
 
 }  // namespace impeller
 
-#endif  // FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
+#endif  // FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
diff --git a/engine/src/flutter/impeller/toolkit/interop/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/toolkit/interop/backend/vulkan/context_vk.cc
index 92e1920..131d75e 100644
--- a/engine/src/flutter/impeller/toolkit/interop/backend/vulkan/context_vk.cc
+++ b/engine/src/flutter/impeller/toolkit/interop/backend/vulkan/context_vk.cc
@@ -53,8 +53,9 @@
   impeller_settings.enable_validation = true;
   sContextVKProcAddressCallback = settings.instance_proc_address_callback;
   impeller_settings.proc_address_callback = ContextVKGetInstanceProcAddress;
-  auto impeller_context = impeller::ContextVK::Create(
-      impeller::Flags{}, std::move(impeller_settings));
+  impeller_settings.flags = impeller::Flags{};
+  auto impeller_context =
+      impeller::ContextVK::Create(std::move(impeller_settings));
   sContextVKProcAddressCallback = nullptr;
   if (!impeller_context) {
     VALIDATION_LOG << "Could not create Impeller context.";
diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json
index c58ca59..97ef7c7 100644
--- a/engine/src/flutter/impeller/tools/malioc.json
+++ b/engine/src/flutter/impeller/tools/malioc.json
@@ -4418,6 +4418,278 @@
       }
     }
   },
+  "flutter/impeller/entity/gles/line.frag.gles": {
+    "Mali-G78": {
+      "core": "Mali-G78",
+      "filename": "flutter/impeller/entity/gles/line.frag.gles",
+      "has_side_effects": false,
+      "has_uniform_computation": false,
+      "modifies_coverage": false,
+      "reads_color_buffer": false,
+      "type": "Fragment",
+      "uses_late_zs_test": false,
+      "uses_late_zs_update": false,
+      "variants": {
+        "Main": {
+          "fp16_arithmetic": 6,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "varying"
+            ],
+            "longest_path_cycles": [
+              0.21875,
+              0.140625,
+              0.21875,
+              0.0,
+              0.0,
+              1.75,
+              0.5
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "varying",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "varying"
+            ],
+            "shortest_path_cycles": [
+              0.140625,
+              0.125,
+              0.140625,
+              0.0,
+              0.0,
+              1.75,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "varying"
+            ],
+            "total_cycles": [
+              0.21875,
+              0.140625,
+              0.21875,
+              0.0,
+              0.0,
+              1.75,
+              0.5
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 4,
+          "work_registers_used": 24
+        }
+      }
+    },
+    "Mali-T880": {
+      "core": "Mali-T880",
+      "filename": "flutter/impeller/entity/gles/line.frag.gles",
+      "has_uniform_computation": false,
+      "type": "Fragment",
+      "variants": {
+        "Main": {
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              3.299999952316284,
+              5.0,
+              2.0
+            ],
+            "pipelines": [
+              "arithmetic",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              2.309999942779541,
+              5.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              3.6666667461395264,
+              5.0,
+              2.0
+            ]
+          },
+          "thread_occupancy": 100,
+          "uniform_registers_used": 1,
+          "work_registers_used": 3
+        }
+      }
+    }
+  },
+  "flutter/impeller/entity/gles/line.vert.gles": {
+    "Mali-G78": {
+      "core": "Mali-G78",
+      "filename": "flutter/impeller/entity/gles/line.vert.gles",
+      "has_uniform_computation": false,
+      "type": "Vertex",
+      "variants": {
+        "Position": {
+          "fp16_arithmetic": 0,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              0.140625,
+              0.140625,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              0.140625,
+              0.140625,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              0.140625,
+              0.140625,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 20,
+          "work_registers_used": 32
+        },
+        "Varying": {
+          "fp16_arithmetic": null,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              0.09375,
+              0.0,
+              0.09375,
+              0.0,
+              10.0,
+              0.0
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              0.09375,
+              0.0,
+              0.09375,
+              0.0,
+              10.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              0.09375,
+              0.0,
+              0.09375,
+              0.0,
+              10.0,
+              0.0
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 8,
+          "work_registers_used": 19
+        }
+      }
+    },
+    "Mali-T880": {
+      "core": "Mali-T880",
+      "filename": "flutter/impeller/entity/gles/line.vert.gles",
+      "has_uniform_computation": false,
+      "type": "Vertex",
+      "variants": {
+        "Main": {
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              2.640000104904175,
+              12.0,
+              0.0
+            ],
+            "pipelines": [
+              "arithmetic",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              2.640000104904175,
+              12.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              2.6666667461395264,
+              12.0,
+              0.0
+            ]
+          },
+          "thread_occupancy": 100,
+          "uniform_registers_used": 5,
+          "work_registers_used": 2
+        }
+      }
+    }
+  },
   "flutter/impeller/entity/gles/linear_gradient_fill.frag.gles": {
     "Mali-G78": {
       "core": "Mali-G78",
@@ -7966,6 +8238,188 @@
       }
     }
   },
+  "flutter/impeller/entity/line.frag.vkspv": {
+    "Mali-G78": {
+      "core": "Mali-G78",
+      "filename": "flutter/impeller/entity/line.frag.vkspv",
+      "has_side_effects": false,
+      "has_uniform_computation": true,
+      "modifies_coverage": false,
+      "reads_color_buffer": false,
+      "type": "Fragment",
+      "uses_late_zs_test": false,
+      "uses_late_zs_update": false,
+      "variants": {
+        "Main": {
+          "fp16_arithmetic": 15,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "varying"
+            ],
+            "longest_path_cycles": [
+              0.1875,
+              0.140625,
+              0.1875,
+              0.1875,
+              0.0,
+              1.75,
+              0.5
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "varying",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "varying"
+            ],
+            "shortest_path_cycles": [
+              0.1875,
+              0.125,
+              0.140625,
+              0.1875,
+              0.0,
+              1.75,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "varying"
+            ],
+            "total_cycles": [
+              0.1875,
+              0.140625,
+              0.1875,
+              0.1875,
+              0.0,
+              1.75,
+              0.5
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 6,
+          "work_registers_used": 18
+        }
+      }
+    }
+  },
+  "flutter/impeller/entity/line.vert.vkspv": {
+    "Mali-G78": {
+      "core": "Mali-G78",
+      "filename": "flutter/impeller/entity/line.vert.vkspv",
+      "has_uniform_computation": true,
+      "type": "Vertex",
+      "variants": {
+        "Position": {
+          "fp16_arithmetic": 0,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              0.125,
+              0.125,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              0.125,
+              0.125,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              0.125,
+              0.125,
+              0.0,
+              0.0,
+              2.0,
+              0.0
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 28,
+          "work_registers_used": 32
+        },
+        "Varying": {
+          "fp16_arithmetic": null,
+          "has_stack_spilling": false,
+          "performance": {
+            "longest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "longest_path_cycles": [
+              0.046875,
+              0.0,
+              0.046875,
+              0.0,
+              10.0,
+              0.0
+            ],
+            "pipelines": [
+              "arith_total",
+              "arith_fma",
+              "arith_cvt",
+              "arith_sfu",
+              "load_store",
+              "texture"
+            ],
+            "shortest_path_bound_pipelines": [
+              "load_store"
+            ],
+            "shortest_path_cycles": [
+              0.046875,
+              0.0,
+              0.046875,
+              0.0,
+              10.0,
+              0.0
+            ],
+            "total_bound_pipelines": [
+              "load_store"
+            ],
+            "total_cycles": [
+              0.046875,
+              0.0,
+              0.046875,
+              0.0,
+              10.0,
+              0.0
+            ]
+          },
+          "stack_spill_bytes": 0,
+          "thread_occupancy": 100,
+          "uniform_registers_used": 20,
+          "work_registers_used": 22
+        }
+      }
+    }
+  },
   "flutter/impeller/entity/linear_gradient_fill.frag.vkspv": {
     "Mali-G78": {
       "core": "Mali-G78",
diff --git a/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm b/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm
index 4639b2a..8383cf0 100644
--- a/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm
+++ b/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm
@@ -40,7 +40,8 @@
   id<MTLDevice> device = nil;
   if (GetSettings().enable_impeller) {
     impeller_context_ =
-        [[FlutterDarwinContextMetalImpeller alloc] init:is_gpu_disabled_sync_switch];
+        [[FlutterDarwinContextMetalImpeller alloc] init:impeller::Flags {}
+                                  gpuDisabledSyncSwitch:is_gpu_disabled_sync_switch];
     FML_CHECK(impeller_context_.context);
     device = impeller_context_.context->GetMTLDevice();
   } else {
diff --git a/engine/src/flutter/shell/common/switches.cc b/engine/src/flutter/shell/common/switches.cc
index ff45ade..eeec695 100644
--- a/engine/src/flutter/shell/common/switches.cc
+++ b/engine/src/flutter/shell/common/switches.cc
@@ -534,6 +534,8 @@
 
   settings.impeller_enable_lazy_shader_mode =
       command_line.HasOption(FlagForSwitch(Switch::ImpellerLazyShaderMode));
+  settings.impeller_antialiased_lines =
+      command_line.HasOption(FlagForSwitch(Switch::ImpellerAntialiasLines));
 
   return settings;
 }
diff --git a/engine/src/flutter/shell/common/switches.h b/engine/src/flutter/shell/common/switches.h
index 02c7d1e..528d3e9 100644
--- a/engine/src/flutter/shell/common/switches.h
+++ b/engine/src/flutter/shell/common/switches.h
@@ -304,6 +304,9 @@
            "impeller-lazy-shader-mode",
            "Whether to defer initialization of all required PSOs for the "
            "Impeller backend. Defaults to false.")
+DEF_SWITCH(ImpellerAntialiasLines,
+           "impeller-antialias-lines",
+           "Experimental flag to test drawing lines with antialiasing.")
 DEF_SWITCHES_END
 
 void PrintUsage(const std::string& executable_name);
diff --git a/engine/src/flutter/shell/platform/android/android_context_vk_impeller.cc b/engine/src/flutter/shell/platform/android/android_context_vk_impeller.cc
index e2b3ede..9815331 100644
--- a/engine/src/flutter/shell/platform/android/android_context_vk_impeller.cc
+++ b/engine/src/flutter/shell/platform/android/android_context_vk_impeller.cc
@@ -48,12 +48,9 @@
   settings.enable_validation = p_settings.enable_validation;
   settings.enable_gpu_tracing = p_settings.enable_gpu_tracing;
   settings.enable_surface_control = p_settings.enable_surface_control;
+  settings.flags = p_settings.impeller_flags;
 
-  auto context = impeller::ContextVK::Create(
-      impeller::Flags{
-          .lazy_shader_mode = p_settings.enable_lazy_shader_mode,
-      },
-      std::move(settings));
+  auto context = impeller::ContextVK::Create(std::move(settings));
 
   if (!p_settings.quiet) {
     if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities())
diff --git a/engine/src/flutter/shell/platform/android/context/android_context.h b/engine/src/flutter/shell/platform/android/context/android_context.h
index 0e4ea0c..e2ac4e9 100644
--- a/engine/src/flutter/shell/platform/android/context/android_context.h
+++ b/engine/src/flutter/shell/platform/android/context/android_context.h
@@ -6,6 +6,7 @@
 #define FLUTTER_SHELL_PLATFORM_ANDROID_CONTEXT_ANDROID_CONTEXT_H_
 
 #include "flutter/fml/macros.h"
+#include "flutter/impeller/base/flags.h"
 #include "flutter/impeller/renderer/context.h"
 #include "flutter/shell/platform/android/android_rendering_selector.h"
 #include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
@@ -25,8 +26,8 @@
     bool enable_validation = false;
     bool enable_gpu_tracing = false;
     bool enable_surface_control = false;
-    bool enable_lazy_shader_mode = false;
     bool quiet = false;
+    impeller::Flags impeller_flags;
   };
 
   AndroidRenderingAPI RenderingApi() const;
diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
index dedd4de..73b28ec 100644
--- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
+++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java
@@ -53,6 +53,8 @@
       "io.flutter.embedding.android.EnableSurfaceControl";
   private static final String IMPELLER_LAZY_SHADER_MODE =
       "io.flutter.embedding.android.ImpellerLazyShaderInitialization";
+  private static final String IMPELLER_ANTIALIAS_LINES =
+      "io.flutter.embedding.android.ImpellerAntialiasLines";
 
   /**
    * Set whether leave or clean up the VM after the last shell shuts down. It can be set from app's
@@ -382,6 +384,9 @@
         if (metaData.getBoolean(IMPELLER_LAZY_SHADER_MODE)) {
           shellArgs.add("--impeller-lazy-shader-mode");
         }
+        if (metaData.getBoolean(IMPELLER_ANTIALIAS_LINES)) {
+          shellArgs.add("--impeller-antialias-lines");
+        }
       }
 
       final String leakVM = isLeakVM(metaData) ? "true" : "false";
diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.cc b/engine/src/flutter/shell/platform/android/platform_view_android.cc
index eb51dbc..caeb2fe 100644
--- a/engine/src/flutter/shell/platform/android/platform_view_android.cc
+++ b/engine/src/flutter/shell/platform/android/platform_view_android.cc
@@ -53,8 +53,10 @@
   settings.enable_gpu_tracing = p_settings.enable_vulkan_gpu_tracing;
   settings.enable_validation = p_settings.enable_vulkan_validation;
   settings.enable_surface_control = p_settings.enable_surface_control;
-  settings.enable_lazy_shader_mode =
+  settings.impeller_flags.lazy_shader_mode =
       p_settings.impeller_enable_lazy_shader_mode;
+  settings.impeller_flags.antialiased_lines =
+      p_settings.impeller_antialiased_lines;
   return settings;
 }
 }  // namespace
diff --git a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
index e4dba21..e004fc2 100644
--- a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
+++ b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
@@ -25,7 +25,9 @@
 /**
  * Initializes a FlutterDarwinContextMetalImpeller.
  */
-- (instancetype)init:(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch;
+- (instancetype)init:(const impeller::Flags&)flags
+    gpuDisabledSyncSwitch:
+        (const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch;
 
 /**
  * Creates an external texture with the specified ID and contents.
diff --git a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm
index 36d95ac..b893da3 100644
--- a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm
+++ b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm
@@ -16,6 +16,7 @@
 FLUTTER_ASSERT_ARC
 
 static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext(
+    const impeller::Flags& flags,
     const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
   std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
       std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data,
@@ -25,16 +26,18 @@
       std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
                                              impeller_framebuffer_blend_shaders_length),
   };
-  return impeller::ContextMTL::Create(impeller::Flags{}, shader_mappings,
-                                      is_gpu_disabled_sync_switch, "Impeller Library");
+  return impeller::ContextMTL::Create(flags, shader_mappings, is_gpu_disabled_sync_switch,
+                                      "Impeller Library");
 }
 
 @implementation FlutterDarwinContextMetalImpeller
 
-- (instancetype)init:(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch {
+- (instancetype)init:(const impeller::Flags&)flags
+    gpuDisabledSyncSwitch:
+        (const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch {
   self = [super init];
   if (self != nil) {
-    _context = CreateImpellerContext(is_gpu_disabled_sync_switch);
+    _context = CreateImpellerContext(flags, is_gpu_disabled_sync_switch);
     FML_CHECK(_context) << "Could not create Metal Impeller Context.";
     id<MTLDevice> device = _context->GetMTLDevice();
     FML_CHECK(device) << "Could not acquire Metal device.";
diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm
index 44459eb..132c581 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm
+++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm
@@ -177,6 +177,9 @@
   settings.enable_wide_gamut = enableWideGamut;
 #endif
 
+  NSNumber* nsAntialiasLines = [mainBundle objectForInfoDictionaryKey:@"FLTAntialiasLines"];
+  settings.impeller_antialiased_lines = (nsAntialiasLines ? nsAntialiasLines.boolValue : NO);
+
   settings.warn_on_impeller_opt_out = true;
 
   NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTTraceSystrace"];
diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context.h b/engine/src/flutter/shell/platform/darwin/ios/ios_context.h
index 24a887a..da8df41 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/ios_context.h
+++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context.h
@@ -9,6 +9,7 @@
 
 #include "flutter/common/graphics/gl_context_switch.h"
 #include "flutter/common/graphics/texture.h"
+#include "flutter/common/settings.h"
 #include "flutter/fml/concurrent_message_loop.h"
 #include "flutter/fml/macros.h"
 #include "flutter/fml/synchronization/sync_switch.h"
@@ -54,7 +55,8 @@
   static std::unique_ptr<IOSContext> Create(
       IOSRenderingAPI api,
       IOSRenderingBackend backend,
-      const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch);
+      const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
+      const Settings& settings);
 
   //----------------------------------------------------------------------------
   /// @brief      Collects the context object. This must happen on the thread on
diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm
index 9517ed8..7db29ea 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm
+++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm
@@ -21,7 +21,8 @@
 std::unique_ptr<IOSContext> IOSContext::Create(
     IOSRenderingAPI api,
     IOSRenderingBackend backend,
-    const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
+    const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
+    const Settings& settings) {
   switch (api) {
     case IOSRenderingAPI::kSoftware:
       FML_LOG(IMPORTANT)
@@ -37,7 +38,7 @@
           FML_LOG(FATAL) << "Impeller opt-out unavailable.";
           return nullptr;
         case IOSRenderingBackend::kImpeller:
-          return std::make_unique<IOSContextMetalImpeller>(is_gpu_disabled_sync_switch);
+          return std::make_unique<IOSContextMetalImpeller>(settings, is_gpu_disabled_sync_switch);
       }
     default:
       break;
diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.h b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.h
index debed10..00f4891 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.h
+++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.h
@@ -21,6 +21,7 @@
 class IOSContextMetalImpeller final : public IOSContext {
  public:
   explicit IOSContextMetalImpeller(
+      const Settings& settings,
       const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch);
 
   ~IOSContextMetalImpeller();
diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm
index 3b9aa5c..83eda04 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm
+++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm
@@ -12,11 +12,20 @@
 FLUTTER_ASSERT_ARC
 
 namespace flutter {
+namespace {
+impeller::Flags SettingsToFlags(const Settings& settings) {
+  return impeller::Flags{
+      .antialiased_lines = settings.impeller_antialiased_lines,
+  };
+}
+}  // namespace
 
 IOSContextMetalImpeller::IOSContextMetalImpeller(
+    const Settings& settings,
     const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch)
-    : darwin_context_metal_impeller_(
-          [[FlutterDarwinContextMetalImpeller alloc] init:is_gpu_disabled_sync_switch]) {
+    : darwin_context_metal_impeller_([[FlutterDarwinContextMetalImpeller alloc]
+                           init:SettingsToFlags(settings)
+          gpuDisabledSyncSwitch:is_gpu_disabled_sync_switch]) {
   if (darwin_context_metal_impeller_.context) {
     aiks_context_ = std::make_shared<impeller::AiksContext>(
         darwin_context_metal_impeller_.context, impeller::TypographerContextSkia::Make());
diff --git a/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm b/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm
index b9b33e8..15f6223 100644
--- a/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm
+++ b/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm
@@ -64,7 +64,8 @@
                                          delegate.OnPlatformViewGetSettings().enable_impeller
                                              ? IOSRenderingBackend::kImpeller
                                              : IOSRenderingBackend::kSkia,
-                                         is_gpu_disabled_sync_switch),
+                                         is_gpu_disabled_sync_switch,
+                                         delegate.OnPlatformViewGetSettings()),
                       platform_views_controller,
                       task_runners) {}
 
diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc
index 6a55973..1017903 100644
--- a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc
+++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc
@@ -71,8 +71,7 @@
   }
   settings.embedder_data = data;
 
-  context_ =
-      impeller::ContextVK::Create(impeller::Flags{}, std::move(settings));
+  context_ = impeller::ContextVK::Create(std::move(settings));
   if (!context_) {
     FML_LOG(ERROR) << "Failed to initialize Vulkan Context.";
     return;
diff --git a/engine/src/flutter/shell/testing/tester_main.cc b/engine/src/flutter/shell/testing/tester_main.cc
index 9a740e3..95bdeb5 100644
--- a/engine/src/flutter/shell/testing/tester_main.cc
+++ b/engine/src/flutter/shell/testing/tester_main.cc
@@ -74,11 +74,11 @@
   context_settings.shader_libraries_data = ShaderLibraryMappings();
   context_settings.cache_directory = fml::paths::GetCachesDirectory();
   context_settings.enable_validation = enable_validation;
+  // Enable lazy shader mode for faster test execution as most tests
+  // will never render anything at all.
+  context_settings.flags.lazy_shader_mode = true;
 
-  context = impeller::ContextVK::Create(
-      // Enable lazy shader mode for faster test execution as most tests
-      // will never render anything at all.
-      impeller::Flags{.lazy_shader_mode = true}, std::move(context_settings));
+  context = impeller::ContextVK::Create(std::move(context_settings));
   if (!context || !context->IsValid()) {
     VALIDATION_LOG << "Could not create Vulkan context.";
     return false;
diff --git a/engine/src/flutter/testing/impeller_golden_tests_output.txt b/engine/src/flutter/testing/impeller_golden_tests_output.txt
index a4e7071..8d3f2b1 100644
--- a/engine/src/flutter/testing/impeller_golden_tests_output.txt
+++ b/engine/src/flutter/testing/impeller_golden_tests_output.txt
@@ -895,6 +895,7 @@
 impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_Metal.png
 impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_OpenGLES.png
 impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_Vulkan.png
+impeller_Play_AiksTest_SimpleExperimentAntialiasLines_Metal.png
 impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_Metal.png
 impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_OpenGLES.png
 impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_Vulkan.png