From 847d93eb738104b1f62658d9497fc6ae97294e0d Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 28 Mar 2024 12:56:03 -0700 Subject: [PATCH 01/49] [Impeller] Optimize away intersect clips that cover the entire pass target. (#51736) I tested against a few example apps and found this case is actually very common. These full screen/pass clips render nothing to the depth buffer can be particularly troublesome in the presence of backdrop filters (due to clip replay). While this case doesn't actually result in anything getting written to the depth buffer, we still end up overwriting the entire stencil buffer twice: Once for the preparation draw, and again for the depth buffer transfer/stencil cleanup draw. --- ci/licenses_golden/excluded_files | 1 + impeller/entity/BUILD.gn | 1 + impeller/entity/contents/clip_contents.cc | 12 ++++ .../contents/clip_contents_unittests.cc | 59 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 impeller/entity/contents/clip_contents_unittests.cc diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 212e9095ac440..a3b47fc20bb3f 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -144,6 +144,7 @@ ../../../flutter/impeller/display_list/skia_conversions_unittests.cc ../../../flutter/impeller/docs ../../../flutter/impeller/entity/contents/checkerboard_contents_unittests.cc +../../../flutter/impeller/entity/contents/clip_contents_unittests.cc ../../../flutter/impeller/entity/contents/content_context_unittests.cc ../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc ../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 9e1a56a21a3c5..b4698a4f1e9d9 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -267,6 +267,7 @@ impeller_component("entity_unittests") { sources = [ "contents/checkerboard_contents_unittests.cc", + "contents/clip_contents_unittests.cc", "contents/content_context_unittests.cc", "contents/filters/gaussian_blur_filter_contents_unittests.cc", "contents/filters/inputs/filter_input_unittests.cc", diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index 4897be855815a..c964a196d9852 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -89,6 +89,18 @@ bool ClipContents::RenderDepthClip(const ContentContext& renderer, const Geometry& geometry) const { using VS = ClipPipeline::VertexShader; + if (clip_op == Entity::ClipOperation::kIntersect && + geometry.IsAxisAlignedRect() && + entity.GetTransform().IsTranslationScaleOnly()) { + std::optional coverage = geometry.GetCoverage(entity.GetTransform()); + if (coverage.has_value() && + coverage->Contains(Rect::MakeSize(pass.GetRenderTargetSize()))) { + // Skip axis-aligned intersect clips that cover the whole render target + // since they won't draw anything to the depth buffer. + return true; + } + } + VS::FrameInfo info; info.depth = GetShaderClipDepth(entity); diff --git a/impeller/entity/contents/clip_contents_unittests.cc b/impeller/entity/contents/clip_contents_unittests.cc new file mode 100644 index 0000000000000..c7fc1dd9d92c1 --- /dev/null +++ b/impeller/entity/contents/clip_contents_unittests.cc @@ -0,0 +1,59 @@ +// 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 +#include + +#include "gtest/gtest.h" + +#include "impeller/entity/contents/checkerboard_contents.h" +#include "impeller/entity/contents/clip_contents.h" +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/contents/test/recording_render_pass.h" +#include "impeller/entity/entity.h" +#include "impeller/entity/entity_playground.h" +#include "impeller/renderer/render_target.h" + +namespace impeller { +namespace testing { + +using EntityTest = EntityPlayground; + +TEST_P(EntityTest, ClipContentsOptimizesFullScreenIntersectClips) { + if (!ContentContext::kEnableStencilThenCover) { + GTEST_SKIP(); + return; + } + + // Set up mock environment. + + auto content_context = GetContentContext(); + auto buffer = content_context->GetContext()->CreateCommandBuffer(); + auto render_target = + GetContentContext()->GetRenderTargetCache()->CreateOffscreenMSAA( + *content_context->GetContext(), {100, 100}, + /*mip_count=*/1); + auto render_pass = buffer->CreateRenderPass(render_target); + auto recording_pass = std::make_shared( + render_pass, GetContext(), render_target); + + // Set up clip contents. + + auto contents = std::make_shared(); + contents->SetClipOperation(Entity::ClipOperation::kIntersect); + contents->SetGeometry(Geometry::MakeCover()); + + Entity entity; + entity.SetContents(std::move(contents)); + + // Render the clip contents. + + ASSERT_TRUE(recording_pass->GetCommands().empty()); + ASSERT_TRUE(entity.Render(*content_context, *recording_pass)); + ASSERT_FALSE(recording_pass->GetCommands().empty()); +} + +} // namespace testing +} // namespace impeller From c176d114d01e4f0fc1890297f53f6e21fd674eb2 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 28 Mar 2024 16:02:10 -0400 Subject: [PATCH 02/49] Roll Skia from c0e0b76d6d51 to e25b0f9006a4 (2 revisions) (#51757) https://skia.googlesource.com/skia.git/+log/c0e0b76d6d51..e25b0f9006a4 2024-03-28 sophiewen@google.com skia: Fix implicit conversion warning 2024-03-28 bungeman@google.com [fontations] Add underline and strikeout metrics If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 26f76ef350e77..facd5b23bba5a 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'c0e0b76d6d519c4d4d1be59e4723d415dd01f24e', + 'skia_revision': 'e25b0f9006a40cdc044f8a9982a820d80d9f1fcb', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0174f11d0237f..33350416a2ef5 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b49ce7cb754a2cffbb08ac9ebfebb98b +Signature: 248fbec3c228f4aa1d6330df92c6e26b ==================================================================================================== LIBRARY: etc1 From b50789f60fef6265ad63c3666f0680f09c217e62 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:36:21 -0700 Subject: [PATCH 03/49] Reland: [Impeller] adds a plus advanced blend for f16 pixel formats (#51756) Relands https://github.com/flutter/engine/pull/51589 The fix is in 74397bc171c74d2bfb24e82b47f2aa29d70c1711. I couldn't figure out how to get a test in the engine to cover it. The test is in the devicelab. Here's what I attempted: ```c++ TEST_P(AiksTest, BlendModePlusAlphaColorFilterAlphaWideGamut) { if (GetParam() != PlaygroundBackend::kMetal) { GTEST_SKIP_("This backend doesn't yet support wide gamut."); } EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), PixelFormat::kR16G16B16A16Float); Canvas canvas; canvas.Scale(GetContentScale()); canvas.DrawPaint({.color = Color(0.1, 0.2, 0.1, 0.5)}); canvas.SaveLayer({ .color_filter = ColorFilter::MakeBlend(BlendMode::kPlus, Color(Vector4{1, 0, 0, 0.5})), }); Paint paint; paint.color = Color(1, 0, 0, 0.5); canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); paint.color = Color::White(); canvas.Restore(); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } ``` ## 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] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- display_list/testing/dl_test_surface_metal.cc | 2 +- impeller/aiks/aiks_unittests.cc | 70 ++++++ .../compiler/shader_lib/impeller/color.glsl | 8 + impeller/core/formats.h | 8 + impeller/entity/contents/content_context.cc | 9 + impeller/entity/contents/content_context.h | 19 ++ .../contents/filters/blend_filter_contents.cc | 75 +++--- .../contents/filters/blend_filter_contents.h | 1 - .../contents/framebuffer_blend_contents.cc | 4 + .../contents/framebuffer_blend_contents.h | 1 + impeller/entity/entity_pass.cc | 7 + .../shaders/blending/advanced_blend.frag | 43 ++-- .../entity/shaders/blending/blend_select.glsl | 5 +- .../shaders/blending/framebuffer_blend.frag | 23 +- impeller/geometry/color.cc | 2 + impeller/geometry/color.h | 2 + impeller/geometry/geometry_unittests.cc | 221 +++++++++--------- .../golden_playground_test_mac.cc | 14 +- impeller/golden_tests/golden_tests.cc | 3 +- impeller/golden_tests/metal_screenshotter.h | 2 +- impeller/golden_tests/metal_screenshotter.mm | 11 +- .../backend/metal/playground_impl_mtl.mm | 9 +- .../playground/compute_playground_test.cc | 2 +- impeller/playground/playground.cc | 5 +- impeller/playground/playground.h | 3 +- impeller/playground/playground_test.cc | 8 +- impeller/playground/switches.h | 2 + impeller/renderer/backend/metal/context_mtl.h | 13 +- .../renderer/backend/metal/context_mtl.mm | 20 +- .../runtime_stage/runtime_stage_unittests.cc | 1 + testing/impeller_golden_tests_output.txt | 5 + 31 files changed, 393 insertions(+), 205 deletions(-) diff --git a/display_list/testing/dl_test_surface_metal.cc b/display_list/testing/dl_test_surface_metal.cc index b7d7f7047bd41..def57908b4671 100644 --- a/display_list/testing/dl_test_surface_metal.cc +++ b/display_list/testing/dl_test_surface_metal.cc @@ -115,7 +115,7 @@ sk_sp DlMetalSurfaceProvider::MakeImpellerImage( void DlMetalSurfaceProvider::InitScreenShotter() const { if (!snapshotter_) { - snapshotter_.reset(new MetalScreenshotter()); + snapshotter_.reset(new MetalScreenshotter(/*enable_wide_gamut=*/false)); auto typographer = impeller::TypographerContextSkia::Make(); aiks_context_.reset(new impeller::AiksContext( snapshotter_->GetPlayground().GetContext(), typographer)); diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 7df6ebd554cb6..39ad0e7fed709 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1102,6 +1102,76 @@ TEST_P(AiksTest, PaintBlendModeIsRespected) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +// This makes sure the WideGamut named tests use 16bit float pixel format. +TEST_P(AiksTest, F16WideGamut) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("This backend doesn't yet support wide gamut."); + } + EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), + PixelFormat::kR16G16B16A16Float); + EXPECT_FALSE(IsAlphaClampedToOne( + GetContext()->GetCapabilities()->GetDefaultColorFormat())); +} + +TEST_P(AiksTest, NotF16) { + EXPECT_TRUE(IsAlphaClampedToOne( + GetContext()->GetCapabilities()->GetDefaultColorFormat())); +} + +// Bug: https://github.com/flutter/flutter/issues/142549 +TEST_P(AiksTest, BlendModePlusAlphaWideGamut) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("This backend doesn't yet support wide gamut."); + } + EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), + PixelFormat::kR16G16B16A16Float); + auto texture = CreateTextureForFixture("airplane.jpg", + /*enable_mipmapping=*/true); + + Canvas canvas; + canvas.Scale(GetContentScale()); + canvas.DrawPaint({.color = Color(0.9, 1.0, 0.9, 1.0)}); + canvas.SaveLayer({}); + Paint paint; + paint.blend_mode = BlendMode::kPlus; + paint.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); + paint.color = Color::White(); + canvas.DrawImageRect( + std::make_shared(texture), Rect::MakeSize(texture->GetSize()), + Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); + canvas.Restore(); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +// Bug: https://github.com/flutter/flutter/issues/142549 +TEST_P(AiksTest, BlendModePlusAlphaColorFilterWideGamut) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("This backend doesn't yet support wide gamut."); + } + EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), + PixelFormat::kR16G16B16A16Float); + auto texture = CreateTextureForFixture("airplane.jpg", + /*enable_mipmapping=*/true); + + Canvas canvas; + canvas.Scale(GetContentScale()); + canvas.DrawPaint({.color = Color(0.1, 0.2, 0.1, 1.0)}); + canvas.SaveLayer({ + .color_filter = + ColorFilter::MakeBlend(BlendMode::kPlus, Color(Vector4{1, 0, 0, 1})), + }); + Paint paint; + paint.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); + paint.color = Color::White(); + canvas.DrawImageRect( + std::make_shared(texture), Rect::MakeSize(texture->GetSize()), + Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); + canvas.Restore(); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, ColorWheel) { // Compare with https://fiddle.skia.org/c/@BlendModes diff --git a/impeller/compiler/shader_lib/impeller/color.glsl b/impeller/compiler/shader_lib/impeller/color.glsl index 310e22e779f76..c497f379fd550 100644 --- a/impeller/compiler/shader_lib/impeller/color.glsl +++ b/impeller/compiler/shader_lib/impeller/color.glsl @@ -46,4 +46,12 @@ f16vec4 IPHalfPremultiply(f16vec4 color) { return f16vec4(color.rgb * color.a, color.a); } +/// Performs the plus blend on `src` and `dst` which are premultiplied colors. +//`max` determines the values the results are clamped to. +f16vec4 IPHalfPlusBlend(f16vec4 src, f16vec4 dst) { + float16_t min = 0.0hf; + float16_t max = 1.0hf; + return clamp(dst + src, min, max); +} + #endif diff --git a/impeller/core/formats.h b/impeller/core/formats.h index aa859b45f6818..108cd454cd2fa 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -138,6 +138,14 @@ constexpr bool IsStencilWritable(PixelFormat format) { } } +/// Returns `true` if the pixel format has an implicit `clamp(x, 0, 1)` in the +/// pixel format. This is important for example when performing the `Plus` blend +/// where we don't want alpha values over 1.0. +constexpr bool IsAlphaClampedToOne(PixelFormat pixel_format) { + return !(pixel_format == PixelFormat::kR32G32B32A32Float || + pixel_format == PixelFormat::kR16G16B16A16Float); +} + constexpr const char* PixelFormatToString(PixelFormat format) { switch (format) { case PixelFormat::kUnknown: diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index f500d1b75c14c..f27096cd876d1 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -124,6 +124,8 @@ void ContentContextOptions::ApplyToPipelineDescriptor( color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; break; case BlendMode::kPlus: + // The kPlusAdvanced should be used instead. + FML_DCHECK(IsAlphaClampedToOne(color_attachment_pixel_format)); color0.dst_alpha_blend_factor = BlendFactor::kOne; color0.dst_color_blend_factor = BlendFactor::kOne; color0.src_alpha_blend_factor = BlendFactor::kOne; @@ -324,6 +326,10 @@ ContentContext::ContentContext( framebuffer_blend_lighten_pipelines_.CreateDefault( *context_, options_trianglestrip, {static_cast(BlendSelectValues::kLighten), supports_decal}); + framebuffer_blend_plus_advanced_pipelines_.CreateDefault( + *context_, options_trianglestrip, + {static_cast(BlendSelectValues::kPlusAdvanced), + supports_decal}); framebuffer_blend_luminosity_pipelines_.CreateDefault( *context_, options_trianglestrip, {static_cast(BlendSelectValues::kLuminosity), supports_decal}); @@ -371,6 +377,9 @@ ContentContext::ContentContext( blend_lighten_pipelines_.CreateDefault( *context_, options_trianglestrip, {static_cast(BlendSelectValues::kLighten), supports_decal}); + blend_plus_advanced_pipelines_.CreateDefault( + *context_, options_trianglestrip, + {static_cast(BlendSelectValues::kPlusAdvanced), supports_decal}); blend_luminosity_pipelines_.CreateDefault( *context_, options_trianglestrip, {static_cast(BlendSelectValues::kLuminosity), supports_decal}); diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index c1eed6ea2fada..5f0380a15461b 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -197,6 +197,8 @@ using BlendHuePipeline = RenderPipelineT; using BlendLightenPipeline = RenderPipelineT; +using BlendPlusAdvancedPipeline = + RenderPipelineT; using BlendLuminosityPipeline = RenderPipelineT; using BlendMultiplyPipeline = @@ -237,6 +239,9 @@ using FramebufferBlendHuePipeline = using FramebufferBlendLightenPipeline = RenderPipelineT; +using FramebufferBlendPlusAdvancedPipeline = + RenderPipelineT; using FramebufferBlendLuminosityPipeline = RenderPipelineT; @@ -640,6 +645,11 @@ class ContentContext { return GetPipeline(blend_lighten_pipelines_, opts); } + std::shared_ptr> GetBlendPlusAdvancedPipeline( + ContentContextOptions opts) const { + return GetPipeline(blend_plus_advanced_pipelines_, opts); + } + std::shared_ptr> GetBlendLuminosityPipeline( ContentContextOptions opts) const { return GetPipeline(blend_luminosity_pipelines_, opts); @@ -725,6 +735,12 @@ class ContentContext { return GetPipeline(framebuffer_blend_lighten_pipelines_, opts); } + std::shared_ptr> + GetFramebufferBlendPlusAdvancedPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch()); + return GetPipeline(framebuffer_blend_plus_advanced_pipelines_, opts); + } + std::shared_ptr> GetFramebufferBlendLuminosityPipeline(ContentContextOptions opts) const { FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch()); @@ -989,6 +1005,7 @@ class ContentContext { mutable Variants blend_hardlight_pipelines_; mutable Variants blend_hue_pipelines_; mutable Variants blend_lighten_pipelines_; + mutable Variants blend_plus_advanced_pipelines_; mutable Variants blend_luminosity_pipelines_; mutable Variants blend_multiply_pipelines_; mutable Variants blend_overlay_pipelines_; @@ -1014,6 +1031,8 @@ class ContentContext { framebuffer_blend_hue_pipelines_; mutable Variants framebuffer_blend_lighten_pipelines_; + mutable Variants + framebuffer_blend_plus_advanced_pipelines_; mutable Variants framebuffer_blend_luminosity_pipelines_; mutable Variants diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 4aadfa3f5ba8f..968fddbf7082d 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -338,6 +338,9 @@ std::optional BlendFilterContents::CreateForegroundAdvancedBlend( case BlendMode::kColor: pass.SetPipeline(renderer.GetBlendColorPipeline(options)); break; + case BlendMode::kPlusAdvanced: + pass.SetPipeline(renderer.GetBlendPlusAdvancedPipeline(options)); + break; case BlendMode::kLuminosity: pass.SetPipeline(renderer.GetBlendLuminosityPipeline(options)); break; @@ -546,7 +549,7 @@ static std::optional PipelineBlend( #define BLEND_CASE(mode) \ case BlendMode::k##mode: \ - advanced_blend_proc_ = \ + return \ [](const FilterInput::Vector& inputs, const ContentContext& renderer, \ const Entity& entity, const Rect& coverage, BlendMode blend_mode, \ std::optional fg_color, \ @@ -559,6 +562,32 @@ static std::optional PipelineBlend( }; \ break; +namespace { +BlendFilterContents::AdvancedBlendProc GetAdvancedBlendProc( + BlendMode blend_mode) { + switch (blend_mode) { + BLEND_CASE(Screen) + BLEND_CASE(Overlay) + BLEND_CASE(Darken) + BLEND_CASE(Lighten) + BLEND_CASE(ColorDodge) + BLEND_CASE(ColorBurn) + BLEND_CASE(HardLight) + BLEND_CASE(SoftLight) + BLEND_CASE(Difference) + BLEND_CASE(Exclusion) + BLEND_CASE(Multiply) + BLEND_CASE(Hue) + BLEND_CASE(Saturation) + BLEND_CASE(Color) + BLEND_CASE(PlusAdvanced) + BLEND_CASE(Luminosity) + default: + FML_UNREACHABLE(); + } +} +} // namespace + void BlendFilterContents::SetBlendMode(BlendMode blend_mode) { if (blend_mode > Entity::kLastAdvancedBlendMode) { VALIDATION_LOG << "Invalid blend mode " << static_cast(blend_mode) @@ -566,28 +595,6 @@ void BlendFilterContents::SetBlendMode(BlendMode blend_mode) { } blend_mode_ = blend_mode; - - if (blend_mode > Entity::kLastPipelineBlendMode) { - switch (blend_mode) { - BLEND_CASE(Screen) - BLEND_CASE(Overlay) - BLEND_CASE(Darken) - BLEND_CASE(Lighten) - BLEND_CASE(ColorDodge) - BLEND_CASE(ColorBurn) - BLEND_CASE(HardLight) - BLEND_CASE(SoftLight) - BLEND_CASE(Difference) - BLEND_CASE(Exclusion) - BLEND_CASE(Multiply) - BLEND_CASE(Hue) - BLEND_CASE(Saturation) - BLEND_CASE(Color) - BLEND_CASE(Luminosity) - default: - FML_UNREACHABLE(); - } - } } void BlendFilterContents::SetForegroundColor(std::optional color) { @@ -611,21 +618,29 @@ std::optional BlendFilterContents::RenderFilter( std::nullopt, GetAbsorbOpacity(), GetAlpha()); } - if (blend_mode_ <= Entity::kLastPipelineBlendMode) { - return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_, + BlendMode blend_mode = blend_mode_; + if (blend_mode == BlendMode::kPlus && + !IsAlphaClampedToOne( + renderer.GetContext()->GetCapabilities()->GetDefaultColorFormat())) { + blend_mode = BlendMode::kPlusAdvanced; + } + + if (blend_mode <= Entity::kLastPipelineBlendMode) { + return PipelineBlend(inputs, renderer, entity, coverage, blend_mode, foreground_color_, GetAbsorbOpacity(), GetAlpha()); } - if (blend_mode_ <= Entity::kLastAdvancedBlendMode) { + if (blend_mode <= Entity::kLastAdvancedBlendMode) { if (inputs.size() == 1 && foreground_color_.has_value() && GetAbsorbOpacity() == ColorFilterContents::AbsorbOpacity::kYes) { return CreateForegroundAdvancedBlend( inputs[0], renderer, entity, coverage, foreground_color_.value(), - blend_mode_, GetAlpha(), GetAbsorbOpacity()); + blend_mode, GetAlpha(), GetAbsorbOpacity()); } - return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode_, - foreground_color_, GetAbsorbOpacity(), - GetAlpha()); + AdvancedBlendProc advanced_blend_proc = GetAdvancedBlendProc(blend_mode); + return advanced_blend_proc(inputs, renderer, entity, coverage, blend_mode, + foreground_color_, GetAbsorbOpacity(), + GetAlpha()); } FML_UNREACHABLE(); diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index 75f575f5b2aaf..5ecdd780c53d2 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -79,7 +79,6 @@ class BlendFilterContents : public ColorFilterContents { ColorFilterContents::AbsorbOpacity absorb_opacity) const; BlendMode blend_mode_ = BlendMode::kSourceOver; - AdvancedBlendProc advanced_blend_proc_; std::optional foreground_color_; BlendFilterContents(const BlendFilterContents&) = delete; diff --git a/impeller/entity/contents/framebuffer_blend_contents.cc b/impeller/entity/contents/framebuffer_blend_contents.cc index c4a75ddd03ab4..cee9b5a904e4c 100644 --- a/impeller/entity/contents/framebuffer_blend_contents.cc +++ b/impeller/entity/contents/framebuffer_blend_contents.cc @@ -118,6 +118,10 @@ bool FramebufferBlendContents::Render(const ContentContext& renderer, case BlendMode::kColor: pass.SetPipeline(renderer.GetFramebufferBlendColorPipeline(options)); break; + case BlendMode::kPlusAdvanced: + pass.SetPipeline( + renderer.GetFramebufferBlendPlusAdvancedPipeline(options)); + break; case BlendMode::kLuminosity: pass.SetPipeline(renderer.GetFramebufferBlendLuminosityPipeline(options)); break; diff --git a/impeller/entity/contents/framebuffer_blend_contents.h b/impeller/entity/contents/framebuffer_blend_contents.h index 5335055bd3f61..c8deee6450b25 100644 --- a/impeller/entity/contents/framebuffer_blend_contents.h +++ b/impeller/entity/contents/framebuffer_blend_contents.h @@ -27,6 +27,7 @@ enum class BlendSelectValues { kHue, kSaturation, kColor, + kPlusAdvanced, kLuminosity, }; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 5637fd8943313..89016da4e5209 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -970,6 +970,13 @@ bool EntityPass::OnRender( /// Setup advanced blends. /// + if (result.entity.GetBlendMode() == BlendMode::kPlus && + !IsAlphaClampedToOne(pass_context.GetPassTarget() + .GetRenderTarget() + .GetRenderTargetPixelFormat())) { + result.entity.SetBlendMode(BlendMode::kPlusAdvanced); + } + if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) { if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) { auto src_contents = result.entity.GetContents(); diff --git a/impeller/entity/shaders/blending/advanced_blend.frag b/impeller/entity/shaders/blending/advanced_blend.frag index db444f522a092..07f72dab63af7 100644 --- a/impeller/entity/shaders/blending/advanced_blend.frag +++ b/impeller/entity/shaders/blending/advanced_blend.frag @@ -36,22 +36,33 @@ f16vec4 Sample(f16sampler2D texture_sampler, vec2 texture_coords) { } void main() { - f16vec4 dst = - IPHalfUnpremultiply(Sample(texture_sampler_dst, // sampler - v_dst_texture_coords // texture coordinates - )); - dst *= blend_info.dst_input_alpha; - f16vec4 src = blend_info.color_factor > 0.0hf - ? blend_info.color - : IPHalfUnpremultiply(Sample( - texture_sampler_src, // sampler - v_src_texture_coords // texture coordinates - )); - if (blend_info.color_factor == 0.0hf) { - src.a *= blend_info.src_input_alpha; - } + f16vec4 premultiplied_dst = + Sample(texture_sampler_dst, // sampler + v_dst_texture_coords // texture coordinates + ); + int nblend_type = int(blend_type); + + if (nblend_type == /*BlendSelectValues::kPlusAdvanced*/ 14) { + f16vec4 premultiplied_src = + Sample(texture_sampler_src, // sampler + v_src_texture_coords // texture coordinates + ); + frag_color = IPHalfPlusBlend(premultiplied_src, premultiplied_dst); + } else { + f16vec4 dst = IPHalfUnpremultiply(premultiplied_dst); + dst *= blend_info.dst_input_alpha; - f16vec3 blend_result = AdvancedBlend(dst.rgb, src.rgb, int(blend_type)); + f16vec4 src = blend_info.color_factor > 0.0hf + ? blend_info.color + : IPHalfUnpremultiply(Sample( + texture_sampler_src, // sampler + v_src_texture_coords // texture coordinates + )); + if (blend_info.color_factor == 0.0hf) { + src.a *= blend_info.src_input_alpha; + } - frag_color = IPApplyBlendedColor(dst, src, blend_result); + f16vec3 blend_result = AdvancedBlend(dst.rgb, src.rgb, nblend_type); + frag_color = IPApplyBlendedColor(dst, src, blend_result); + } } diff --git a/impeller/entity/shaders/blending/blend_select.glsl b/impeller/entity/shaders/blending/blend_select.glsl index 17c45c16fdcf4..b03e6eb520abd 100644 --- a/impeller/entity/shaders/blending/blend_select.glsl +++ b/impeller/entity/shaders/blending/blend_select.glsl @@ -20,6 +20,7 @@ // kHue, // kSaturation, // kColor, +// kPlusAdvanced, // kLuminosity, // Note, this isn't a switch as GLSL ES 1.0 does not support them. f16vec3 AdvancedBlend(f16vec3 dst, f16vec3 src, int blend_type) { @@ -65,7 +66,9 @@ f16vec3 AdvancedBlend(f16vec3 dst, f16vec3 src, int blend_type) { if (blend_type == 13) { return IPBlendColor(dst, src); } - if (blend_type == 14) { + // 14 is `PlusAdvanced`, it's handled in advanced_blend.frag and + // framebuffer_blend.frag. + if (blend_type == 15) { return IPBlendLuminosity(dst, src); } return f16vec3(0.0hf); diff --git a/impeller/entity/shaders/blending/framebuffer_blend.frag b/impeller/entity/shaders/blending/framebuffer_blend.frag index 6d03856b4a824..1eba2de9a9b3a 100644 --- a/impeller/entity/shaders/blending/framebuffer_blend.frag +++ b/impeller/entity/shaders/blending/framebuffer_blend.frag @@ -43,14 +43,21 @@ vec4 Sample(sampler2D texture_sampler, vec2 texture_coords) { } void main() { - f16vec4 dst = IPHalfUnpremultiply(f16vec4(ReadDestination())); - f16vec4 src = IPHalfUnpremultiply( + f16vec4 premultiplied_dst = f16vec4(ReadDestination()); + f16vec4 premultiplied_src = f16vec4(Sample(texture_sampler_src, // sampler v_src_texture_coords // texture coordinates - ))); - src.a *= frag_info.src_input_alpha; - - f16vec3 blend_result = AdvancedBlend(dst.rgb, src.rgb, int(blend_type)); - - frag_color = IPApplyBlendedColor(dst, src, blend_result); + )); + int nblend_type = int(blend_type); + + if (nblend_type == /*BlendSelectValues::kPlusAdvanced*/ 14) { + frag_color = IPHalfPlusBlend(premultiplied_src, premultiplied_dst); + } else { + f16vec4 dst = IPHalfUnpremultiply(premultiplied_dst); + f16vec4 src = IPHalfUnpremultiply(premultiplied_src); + src.a *= frag_info.src_input_alpha; + + f16vec3 blend_result = AdvancedBlend(dst.rgb, src.rgb, nblend_type); + frag_color = IPApplyBlendedColor(dst, src, blend_result); + } } diff --git a/impeller/geometry/color.cc b/impeller/geometry/color.cc index d2565e6e6fd1d..a8c70e1862359 100644 --- a/impeller/geometry/color.cc +++ b/impeller/geometry/color.cc @@ -276,6 +276,8 @@ Color Color::Blend(Color src, BlendMode blend_mode) const { return (src.Premultiply() * (1 - dst.alpha) + dst.Premultiply() * (1 - src.alpha)) .Unpremultiply(); + case BlendMode::kPlusAdvanced: + [[fallthrough]]; case BlendMode::kPlus: // r = min(s + d, 1) return (Min(src.Premultiply() + dst.Premultiply(), 1)).Unpremultiply(); diff --git a/impeller/geometry/color.h b/impeller/geometry/color.h index c90c696066ed6..59805e952ec02 100644 --- a/impeller/geometry/color.h +++ b/impeller/geometry/color.h @@ -45,6 +45,7 @@ V(Hue) \ V(Saturation) \ V(Color) \ + V(PlusAdvanced) \ V(Luminosity) namespace impeller { @@ -91,6 +92,7 @@ enum class BlendMode : uint8_t { kHue, kSaturation, kColor, + kPlusAdvanced, kLuminosity, kLast = kLuminosity, diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index aa1e5910b77eb..af9a2a1cfe9df 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -6,6 +6,7 @@ #include "impeller/geometry/geometry_asserts.h" #include +#include #include #include @@ -1450,107 +1451,112 @@ struct ColorBlendTestData { Color::LimeGreen().WithAlpha(0.75), Color::Black().WithAlpha(0.75)}; - // THIS RESULT TABLE IS GENERATED! - // - // Uncomment the `GenerateColorBlendResults` test below to print a new table - // after making changes to `Color::Blend`. - static constexpr Color kExpectedResults - [sizeof(kSourceColors)] - [static_cast>(BlendMode::kLast) + 1] = { - { - {0, 0, 0, 0}, // Clear - {1, 1, 1, 0.75}, // Source - {0.392157, 0.584314, 0.929412, 0.75}, // Destination - {0.878431, 0.916863, 0.985882, 0.9375}, // SourceOver - {0.513726, 0.667451, 0.943529, 0.9375}, // DestinationOver - {1, 1, 1, 0.5625}, // SourceIn - {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn - {1, 1, 1, 0.1875}, // SourceOut - {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut - {0.848039, 0.896078, 0.982353, 0.75}, // SourceATop - {0.544118, 0.688235, 0.947059, 0.75}, // DestinationATop - {0.696078, 0.792157, 0.964706, 0.375}, // Xor - {1, 1, 1, 1}, // Plus - {0.392157, 0.584314, 0.929412, 0.5625}, // Modulate - {0.878431, 0.916863, 0.985882, 0.9375}, // Screen - {0.74902, 0.916863, 0.985882, 0.9375}, // Overlay - {0.513726, 0.667451, 0.943529, 0.9375}, // Darken - {0.878431, 0.916863, 0.985882, 0.9375}, // Lighten - {0.878431, 0.916863, 0.985882, 0.9375}, // ColorDodge - {0.513725, 0.667451, 0.943529, 0.9375}, // ColorBurn - {0.878431, 0.916863, 0.985882, 0.9375}, // HardLight - {0.654166, 0.775505, 0.964318, 0.9375}, // SoftLight - {0.643137, 0.566275, 0.428235, 0.9375}, // Difference - {0.643137, 0.566275, 0.428235, 0.9375}, // Exclusion - {0.513726, 0.667451, 0.943529, 0.9375}, // Multiply - {0.617208, 0.655639, 0.724659, 0.9375}, // Hue - {0.617208, 0.655639, 0.724659, 0.9375}, // Saturation - {0.617208, 0.655639, 0.724659, 0.9375}, // Color - {0.878431, 0.916863, 0.985882, 0.9375}, // Luminosity - }, - { - {0, 0, 0, 0}, // Clear - {0.196078, 0.803922, 0.196078, 0.75}, // Source - {0.392157, 0.584314, 0.929412, 0.75}, // Destination - {0.235294, 0.76, 0.342745, 0.9375}, // SourceOver - {0.352941, 0.628235, 0.782745, 0.9375}, // DestinationOver - {0.196078, 0.803922, 0.196078, 0.5625}, // SourceIn - {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn - {0.196078, 0.803922, 0.196078, 0.1875}, // SourceOut - {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut - {0.245098, 0.74902, 0.379412, 0.75}, // SourceATop - {0.343137, 0.639216, 0.746078, 0.75}, // DestinationATop - {0.294118, 0.694118, 0.562745, 0.375}, // Xor - {0.441176, 1, 0.844118, 1}, // Plus - {0.0768935, 0.469742, 0.182238, 0.5625}, // Modulate - {0.424452, 0.828743, 0.79105, 0.9375}, // Screen - {0.209919, 0.779839, 0.757001, 0.9375}, // Overlay - {0.235294, 0.628235, 0.342745, 0.9375}, // Darken - {0.352941, 0.76, 0.782745, 0.9375}, // Lighten - {0.41033, 0.877647, 0.825098, 0.9375}, // ColorDodge - {0.117647, 0.567403, 0.609098, 0.9375}, // ColorBurn - {0.209919, 0.779839, 0.443783, 0.9375}, // HardLight - {0.266006, 0.693915, 0.758818, 0.9375}, // SoftLight - {0.235294, 0.409412, 0.665098, 0.9375}, // Difference - {0.378316, 0.546897, 0.681707, 0.9375}, // Exclusion - {0.163783, 0.559493, 0.334441, 0.9375}, // Multiply - {0.266235, 0.748588, 0.373686, 0.9375}, // Hue - {0.339345, 0.629787, 0.811502, 0.9375}, // Saturation - {0.241247, 0.765953, 0.348698, 0.9375}, // Color - {0.346988, 0.622282, 0.776792, 0.9375}, // Luminosity - }, - { - {0, 0, 0, 0}, // Clear - {0, 0, 0, 0.75}, // Source - {0.392157, 0.584314, 0.929412, 0.75}, // Destination - {0.0784314, 0.116863, 0.185882, 0.9375}, // SourceOver - {0.313726, 0.467451, 0.743529, 0.9375}, // DestinationOver - {0, 0, 0, 0.5625}, // SourceIn - {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn - {0, 0, 0, 0.1875}, // SourceOut - {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut - {0.0980392, 0.146078, 0.232353, 0.75}, // SourceATop - {0.294118, 0.438235, 0.697059, 0.75}, // DestinationATop - {0.196078, 0.292157, 0.464706, 0.375}, // Xor - {0.294118, 0.438235, 0.697059, 1}, // Plus - {0, 0, 0, 0.5625}, // Modulate - {0.313726, 0.467451, 0.743529, 0.9375}, // Screen - {0.0784314, 0.218039, 0.701176, 0.9375}, // Overlay - {0.0784314, 0.116863, 0.185882, 0.9375}, // Darken - {0.313726, 0.467451, 0.743529, 0.9375}, // Lighten - {0.313726, 0.467451, 0.743529, 0.9375}, // ColorDodge - {0.0784314, 0.116863, 0.185882, 0.9375}, // ColorBurn - {0.0784314, 0.116863, 0.185882, 0.9375}, // HardLight - {0.170704, 0.321716, 0.704166, 0.9375}, // SoftLight - {0.313726, 0.467451, 0.743529, 0.9375}, // Difference - {0.313726, 0.467451, 0.743529, 0.9375}, // Exclusion - {0.0784314, 0.116863, 0.185882, 0.9375}, // Multiply - {0.417208, 0.455639, 0.524659, 0.9375}, // Hue - {0.417208, 0.455639, 0.524659, 0.9375}, // Saturation - {0.417208, 0.455639, 0.524659, 0.9375}, // Color - {0.0784314, 0.116863, 0.185882, 0.9375}, // Luminosity - }, - }; + static const std::map + kExpectedResults[sizeof(kSourceColors)]; +}; + +// THIS RESULT TABLE IS GENERATED! +// +// Uncomment the `GenerateColorBlendResults` test below to print a new table +// after making changes to `Color::Blend`. +const std::map ColorBlendTestData::kExpectedResults[sizeof( + ColorBlendTestData::kSourceColors)] = { + { + {BlendMode::kClear, {0, 0, 0, 0}}, + {BlendMode::kSource, {1, 1, 1, 0.75}}, + {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}}, + {BlendMode::kSourceOver, {0.878431, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kDestinationOver, {0.513726, 0.667451, 0.943529, 0.9375}}, + {BlendMode::kSourceIn, {1, 1, 1, 0.5625}}, + {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}}, + {BlendMode::kSourceOut, {1, 1, 1, 0.1875}}, + {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}}, + {BlendMode::kSourceATop, {0.848039, 0.896078, 0.982353, 0.75}}, + {BlendMode::kDestinationATop, {0.544118, 0.688235, 0.947059, 0.75}}, + {BlendMode::kXor, {0.696078, 0.792157, 0.964706, 0.375}}, + {BlendMode::kPlus, {1, 1, 1, 1}}, + {BlendMode::kModulate, {0.392157, 0.584314, 0.929412, 0.5625}}, + {BlendMode::kScreen, {0.878431, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kOverlay, {0.74902, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kDarken, {0.513726, 0.667451, 0.943529, 0.9375}}, + {BlendMode::kLighten, {0.878431, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kColorDodge, {0.878431, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kColorBurn, {0.513725, 0.667451, 0.943529, 0.9375}}, + {BlendMode::kHardLight, {0.878431, 0.916863, 0.985882, 0.9375}}, + {BlendMode::kSoftLight, {0.654166, 0.775505, 0.964318, 0.9375}}, + {BlendMode::kDifference, {0.643137, 0.566275, 0.428235, 0.9375}}, + {BlendMode::kExclusion, {0.643137, 0.566275, 0.428235, 0.9375}}, + {BlendMode::kMultiply, {0.513726, 0.667451, 0.943529, 0.9375}}, + {BlendMode::kHue, {0.617208, 0.655639, 0.724659, 0.9375}}, + {BlendMode::kSaturation, {0.617208, 0.655639, 0.724659, 0.9375}}, + {BlendMode::kColor, {0.617208, 0.655639, 0.724659, 0.9375}}, + {BlendMode::kPlusAdvanced, {1, 1, 1, 1}}, + {BlendMode::kLuminosity, {0.878431, 0.916863, 0.985882, 0.9375}}, + }, + { + {BlendMode::kClear, {0, 0, 0, 0}}, + {BlendMode::kSource, {0.196078, 0.803922, 0.196078, 0.75}}, + {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}}, + {BlendMode::kSourceOver, {0.235294, 0.76, 0.342745, 0.9375}}, + {BlendMode::kDestinationOver, {0.352941, 0.628235, 0.782745, 0.9375}}, + {BlendMode::kSourceIn, {0.196078, 0.803922, 0.196078, 0.5625}}, + {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}}, + {BlendMode::kSourceOut, {0.196078, 0.803922, 0.196078, 0.1875}}, + {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}}, + {BlendMode::kSourceATop, {0.245098, 0.74902, 0.379412, 0.75}}, + {BlendMode::kDestinationATop, {0.343137, 0.639216, 0.746078, 0.75}}, + {BlendMode::kXor, {0.294118, 0.694118, 0.562745, 0.375}}, + {BlendMode::kPlus, {0.441176, 1, 0.844118, 1}}, + {BlendMode::kModulate, {0.0768935, 0.469742, 0.182238, 0.5625}}, + {BlendMode::kScreen, {0.424452, 0.828743, 0.79105, 0.9375}}, + {BlendMode::kOverlay, {0.209919, 0.779839, 0.757001, 0.9375}}, + {BlendMode::kDarken, {0.235294, 0.628235, 0.342745, 0.9375}}, + {BlendMode::kLighten, {0.352941, 0.76, 0.782745, 0.9375}}, + {BlendMode::kColorDodge, {0.41033, 0.877647, 0.825098, 0.9375}}, + {BlendMode::kColorBurn, {0.117647, 0.567403, 0.609098, 0.9375}}, + {BlendMode::kHardLight, {0.209919, 0.779839, 0.443783, 0.9375}}, + {BlendMode::kSoftLight, {0.266006, 0.693915, 0.758818, 0.9375}}, + {BlendMode::kDifference, {0.235294, 0.409412, 0.665098, 0.9375}}, + {BlendMode::kExclusion, {0.378316, 0.546897, 0.681707, 0.9375}}, + {BlendMode::kMultiply, {0.163783, 0.559493, 0.334441, 0.9375}}, + {BlendMode::kHue, {0.266235, 0.748588, 0.373686, 0.9375}}, + {BlendMode::kSaturation, {0.339345, 0.629787, 0.811502, 0.9375}}, + {BlendMode::kColor, {0.241247, 0.765953, 0.348698, 0.9375}}, + {BlendMode::kPlusAdvanced, {0.441176, 1, 0.844118, 1}}, + {BlendMode::kLuminosity, {0.346988, 0.622282, 0.776792, 0.9375}}, + }, + { + {BlendMode::kClear, {0, 0, 0, 0}}, + {BlendMode::kSource, {0, 0, 0, 0.75}}, + {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}}, + {BlendMode::kSourceOver, {0.0784314, 0.116863, 0.185882, 0.9375}}, + {BlendMode::kDestinationOver, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kSourceIn, {0, 0, 0, 0.5625}}, + {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}}, + {BlendMode::kSourceOut, {0, 0, 0, 0.1875}}, + {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}}, + {BlendMode::kSourceATop, {0.0980392, 0.146078, 0.232353, 0.75}}, + {BlendMode::kDestinationATop, {0.294118, 0.438235, 0.697059, 0.75}}, + {BlendMode::kXor, {0.196078, 0.292157, 0.464706, 0.375}}, + {BlendMode::kPlus, {0.294118, 0.438235, 0.697059, 1}}, + {BlendMode::kModulate, {0, 0, 0, 0.5625}}, + {BlendMode::kScreen, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kOverlay, {0.0784314, 0.218039, 0.701176, 0.9375}}, + {BlendMode::kDarken, {0.0784314, 0.116863, 0.185882, 0.9375}}, + {BlendMode::kLighten, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kColorDodge, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kColorBurn, {0.0784314, 0.116863, 0.185882, 0.9375}}, + {BlendMode::kHardLight, {0.0784314, 0.116863, 0.185882, 0.9375}}, + {BlendMode::kSoftLight, {0.170704, 0.321716, 0.704166, 0.9375}}, + {BlendMode::kDifference, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kExclusion, {0.313726, 0.467451, 0.743529, 0.9375}}, + {BlendMode::kMultiply, {0.0784314, 0.116863, 0.185882, 0.9375}}, + {BlendMode::kHue, {0.417208, 0.455639, 0.524659, 0.9375}}, + {BlendMode::kSaturation, {0.417208, 0.455639, 0.524659, 0.9375}}, + {BlendMode::kColor, {0.417208, 0.455639, 0.524659, 0.9375}}, + {BlendMode::kPlusAdvanced, {0.294118, 0.438235, 0.697059, 1}}, + {BlendMode::kLuminosity, {0.0784314, 0.116863, 0.185882, 0.9375}}, + }, }; /// To print a new ColorBlendTestData::kExpectedResults table, uncomment this @@ -1567,8 +1573,10 @@ TEST(GeometryTest, GenerateColorBlendResults) { blend_i < static_cast(BlendMode::kLast) + 1; blend_i++) { auto blend = static_cast(blend_i); Color c = ColorBlendTestData::kDestinationColor.Blend(source, blend); + o << "{ BlendMode::k" << BlendModeToString(blend) << ", "; o << "{" << c.red << "," << c.green << "," << c.blue << "," << c.alpha - << "}, // " << BlendModeToString(blend) << std::endl; + << "}"; + o << "}," << std::endl; } o << "},"; } @@ -1576,20 +1584,19 @@ TEST(GeometryTest, GenerateColorBlendResults) { } */ -#define _BLEND_MODE_RESULT_CHECK(blend_mode) \ - blend_i = static_cast(BlendMode::k##blend_mode); \ - expected = ColorBlendTestData::kExpectedResults[source_i][blend_i]; \ +#define _BLEND_MODE_RESULT_CHECK(blend_mode) \ + expected = ColorBlendTestData::kExpectedResults[source_i] \ + .find(BlendMode::k##blend_mode) \ + ->second; \ EXPECT_COLOR_NEAR(dst.Blend(src, BlendMode::k##blend_mode), expected); TEST(GeometryTest, ColorBlendReturnsExpectedResults) { - using BlendT = std::underlying_type_t; Color dst = ColorBlendTestData::kDestinationColor; for (size_t source_i = 0; source_i < sizeof(ColorBlendTestData::kSourceColors) / sizeof(Color); source_i++) { Color src = ColorBlendTestData::kSourceColors[source_i]; - size_t blend_i; Color expected; IMPELLER_FOR_EACH_BLEND_MODE(_BLEND_MODE_RESULT_CHECK) } diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index 75fea0f34072a..833a62bfbf0a1 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -138,9 +138,12 @@ void GoldenPlaygroundTest::SetUp() { std::filesystem::path icd_path = target_path / "vk_swiftshader_icd.json"; 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; switch (GetParam()) { case PlaygroundBackend::kMetal: - pimpl_->screenshotter = std::make_unique(); + pimpl_->screenshotter = + std::make_unique(enable_wide_gamut); break; case PlaygroundBackend::kVulkan: { const std::unique_ptr& playground = @@ -160,16 +163,7 @@ void GoldenPlaygroundTest::SetUp() { break; } } - if (GetParam() == PlaygroundBackend::kMetal) { - pimpl_->screenshotter = std::make_unique(); - } else if (GetParam() == PlaygroundBackend::kVulkan) { - const std::unique_ptr& playground = - GetSharedVulkanPlayground(/*enable_validations=*/true); - pimpl_->screenshotter = - std::make_unique(playground); - } - std::string test_name = GetTestName(); if (std::find(kSkipTests.begin(), kSkipTests.end(), test_name) != kSkipTests.end()) { GTEST_SKIP_( diff --git a/impeller/golden_tests/golden_tests.cc b/impeller/golden_tests/golden_tests.cc index c519f367a1ddb..40a79cd173703 100644 --- a/impeller/golden_tests/golden_tests.cc +++ b/impeller/golden_tests/golden_tests.cc @@ -50,7 +50,8 @@ bool SaveScreenshot(std::unique_ptr screenshot) { class GoldenTests : public ::testing::Test { public: - GoldenTests() : screenshotter_(new MetalScreenshotter()) {} + GoldenTests() + : screenshotter_(new MetalScreenshotter(/*enable_wide_gamut=*/false)) {} MetalScreenshotter& Screenshotter() { return *screenshotter_; } diff --git a/impeller/golden_tests/metal_screenshotter.h b/impeller/golden_tests/metal_screenshotter.h index 582462a73f425..8104396bd8be5 100644 --- a/impeller/golden_tests/metal_screenshotter.h +++ b/impeller/golden_tests/metal_screenshotter.h @@ -18,7 +18,7 @@ namespace testing { /// playground backend. class MetalScreenshotter : public Screenshotter { public: - MetalScreenshotter(); + explicit MetalScreenshotter(bool enable_wide_gamut); std::unique_ptr MakeScreenshot( AiksContext& aiks_context, diff --git a/impeller/golden_tests/metal_screenshotter.mm b/impeller/golden_tests/metal_screenshotter.mm index 534884078a17f..f09cb10e03849 100644 --- a/impeller/golden_tests/metal_screenshotter.mm +++ b/impeller/golden_tests/metal_screenshotter.mm @@ -13,10 +13,11 @@ namespace impeller { namespace testing { -MetalScreenshotter::MetalScreenshotter() { +MetalScreenshotter::MetalScreenshotter(bool enable_wide_gamut) { FML_CHECK(::glfwInit() == GLFW_TRUE); - playground_ = - PlaygroundImpl::Create(PlaygroundBackend::kMetal, PlaygroundSwitches{}); + PlaygroundSwitches switches; + switches.enable_wide_gamut = enable_wide_gamut; + playground_ = PlaygroundImpl::Create(PlaygroundBackend::kMetal, switches); } std::unique_ptr MetalScreenshotter::MakeScreenshot( @@ -33,10 +34,6 @@ id metal_texture = std::static_pointer_cast(texture)->GetMTLTexture(); - if (metal_texture.pixelFormat != MTLPixelFormatBGRA8Unorm) { - return {}; - } - CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); CIImage* ciImage = [[CIImage alloc] initWithMTLTexture:metal_texture diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 421d6eba3c46b..00babefd4c047 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -73,9 +73,12 @@ if (!window) { return; } - auto context = - ContextMTL::Create(ShaderLibraryMappingsForPlayground(), - is_gpu_disabled_sync_switch_, "Playground Library"); + auto context = ContextMTL::Create( + ShaderLibraryMappingsForPlayground(), is_gpu_disabled_sync_switch_, + "Playground Library", + switches.enable_wide_gamut + ? std::optional(PixelFormat::kR16G16B16A16Float) + : std::nullopt); if (!context) { return; } diff --git a/impeller/playground/compute_playground_test.cc b/impeller/playground/compute_playground_test.cc index 3df0e62a7260e..1abea913ebea4 100644 --- a/impeller/playground/compute_playground_test.cc +++ b/impeller/playground/compute_playground_test.cc @@ -25,7 +25,7 @@ void ComputePlaygroundTest::SetUp() { return; } - SetupContext(GetParam()); + SetupContext(GetParam(), switches_); SetupWindow(); start_time_ = fml::TimePoint::Now().ToEpochDelta(); diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 4ed9e5af7efcb..ae4d7cd4dd3fb 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -120,10 +120,11 @@ bool Playground::SupportsBackend(PlaygroundBackend backend) { FML_UNREACHABLE(); } -void Playground::SetupContext(PlaygroundBackend backend) { +void Playground::SetupContext(PlaygroundBackend backend, + const PlaygroundSwitches& switches) { FML_CHECK(SupportsBackend(backend)); - impl_ = PlaygroundImpl::Create(backend, switches_); + impl_ = PlaygroundImpl::Create(backend, switches); if (!impl_) { FML_LOG(WARNING) << "PlaygroundImpl::Create failed."; return; diff --git a/impeller/playground/playground.h b/impeller/playground/playground.h index 9c6cde6467d6a..b15461272f3d5 100644 --- a/impeller/playground/playground.h +++ b/impeller/playground/playground.h @@ -57,7 +57,8 @@ class Playground { static bool ShouldOpenNewPlaygrounds(); - void SetupContext(PlaygroundBackend backend); + void SetupContext(PlaygroundBackend backend, + const PlaygroundSwitches& switches); void SetupWindow(); diff --git a/impeller/playground/playground_test.cc b/impeller/playground/playground_test.cc index 676c3b0412992..00ee371ce2fbb 100644 --- a/impeller/playground/playground_test.cc +++ b/impeller/playground/playground_test.cc @@ -28,7 +28,13 @@ void PlaygroundTest::SetUp() { ImpellerValidationErrorsSetFatal(true); - SetupContext(GetParam()); + // Test names that end with "WideGamut" will render with wide gamut support. + std::string test_name = flutter::testing::GetCurrentTestName(); + PlaygroundSwitches switches = switches_; + switches.enable_wide_gamut = + test_name.find("WideGamut/") != std::string::npos; + + SetupContext(GetParam(), switches); SetupWindow(); } diff --git a/impeller/playground/switches.h b/impeller/playground/switches.h index be49fb0191a9b..6b9df55eb7642 100644 --- a/impeller/playground/switches.h +++ b/impeller/playground/switches.h @@ -33,6 +33,8 @@ struct PlaygroundSwitches { /// bool use_angle = false; + bool enable_wide_gamut = false; + PlaygroundSwitches(); explicit PlaygroundSwitches(const fml::CommandLine& args); diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 6497871b28b25..dd11641665128 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -43,7 +43,8 @@ class ContextMTL final : public Context, static std::shared_ptr Create( const std::vector>& shader_libraries_data, std::shared_ptr is_gpu_disabled_sync_switch, - const std::string& label); + const std::string& label, + std::optional pixel_format_override = std::nullopt); static std::shared_ptr Create( id device, @@ -133,11 +134,11 @@ class ContextMTL final : public Context, std::shared_ptr command_queue_ip_; bool is_valid_ = false; - ContextMTL( - id device, - id command_queue, - NSArray>* shader_libraries, - std::shared_ptr is_gpu_disabled_sync_switch); + ContextMTL(id device, + id command_queue, + NSArray>* shader_libraries, + std::shared_ptr is_gpu_disabled_sync_switch, + std::optional pixel_format_override = std::nullopt); std::shared_ptr CreateCommandBufferInQueue( id queue) const; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 623f3c8335f4c..6248368687451 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -75,7 +75,8 @@ static bool DeviceSupportsComputeSubgroups(id device) { id device, id command_queue, NSArray>* shader_libraries, - std::shared_ptr is_gpu_disabled_sync_switch) + std::shared_ptr is_gpu_disabled_sync_switch, + std::optional pixel_format_override) : device_(device), command_queue_(command_queue), is_gpu_disabled_sync_switch_(std::move(is_gpu_disabled_sync_switch)) { @@ -128,7 +129,9 @@ static bool DeviceSupportsComputeSubgroups(id device) { } device_capabilities_ = - InferMetalCapabilities(device_, PixelFormat::kB8G8R8A8UNormInt); + InferMetalCapabilities(device_, pixel_format_override.has_value() + ? pixel_format_override.value() + : PixelFormat::kB8G8R8A8UNormInt); command_queue_ip_ = std::make_shared(); #ifdef IMPELLER_DEBUG gpu_tracer_ = std::make_shared(); @@ -238,17 +241,18 @@ static bool DeviceSupportsComputeSubgroups(id device) { std::shared_ptr ContextMTL::Create( const std::vector>& shader_libraries_data, std::shared_ptr is_gpu_disabled_sync_switch, - const std::string& library_label) { + const std::string& library_label, + std::optional pixel_format_override) { auto device = CreateMetalDevice(); auto command_queue = CreateMetalCommandQueue(device); if (!command_queue) { return nullptr; } - auto context = std::shared_ptr( - new ContextMTL(device, command_queue, - MTLShaderLibraryFromFileData(device, shader_libraries_data, - library_label), - std::move(is_gpu_disabled_sync_switch))); + auto context = std::shared_ptr(new ContextMTL( + device, command_queue, + MTLShaderLibraryFromFileData(device, shader_libraries_data, + library_label), + std::move(is_gpu_disabled_sync_switch), pixel_format_override)); if (!context->IsValid()) { FML_LOG(ERROR) << "Could not create Metal context."; return nullptr; diff --git a/impeller/runtime_stage/runtime_stage_unittests.cc b/impeller/runtime_stage/runtime_stage_unittests.cc index 8315c6af7c455..2dc646d3a640b 100644 --- a/impeller/runtime_stage/runtime_stage_unittests.cc +++ b/impeller/runtime_stage/runtime_stage_unittests.cc @@ -62,6 +62,7 @@ TEST_P(RuntimeStageTest, CanReadUniforms) { ASSERT_TRUE(stage->IsValid()); switch (GetBackend()) { case PlaygroundBackend::kMetal: + [[fallthrough]]; case PlaygroundBackend::kOpenGLES: { ASSERT_EQ(stage->GetUniforms().size(), 17u); { diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 6f301c29df503..ae8814380b1f8 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -57,6 +57,11 @@ impeller_Play_AiksTest_BlendModeMultiply_Vulkan.png impeller_Play_AiksTest_BlendModeOverlay_Metal.png impeller_Play_AiksTest_BlendModeOverlay_OpenGLES.png impeller_Play_AiksTest_BlendModeOverlay_Vulkan.png +impeller_Play_AiksTest_BlendModePlusAdvanced_Metal.png +impeller_Play_AiksTest_BlendModePlusAdvanced_OpenGLES.png +impeller_Play_AiksTest_BlendModePlusAdvanced_Vulkan.png +impeller_Play_AiksTest_BlendModePlusAlphaColorFilterWideGamut_Metal.png +impeller_Play_AiksTest_BlendModePlusAlphaWideGamut_Metal.png impeller_Play_AiksTest_BlendModePlus_Metal.png impeller_Play_AiksTest_BlendModePlus_OpenGLES.png impeller_Play_AiksTest_BlendModePlus_Vulkan.png From a8338a4ea1d5b44019ac11e585eac507dda731e8 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 28 Mar 2024 13:46:53 -0700 Subject: [PATCH 04/49] Remove Android API v33 tests from CI. (#51751) Closes https://github.com/flutter/flutter/issues/144064. From a conversation with @camsim99 on Discord: > Ah this was to debug that missing emulator issue (https://github.com/flutter/flutter/issues/137947) that Ricardo and I were seeing. We wanted to see if it was specific to the API 34, and if so, escalate the issue internally. @ricardoamador Would you like to keep running the tests with API 33? You mentioned you have found a workaround, and the test runs seem to not have yielded any evidence against API 34. --- .ci.yaml | 23 ----- .../linux_android_emulator_api_33.json | 88 ------------------- 2 files changed, 111 deletions(-) delete mode 100644 ci/builders/linux_android_emulator_api_33.json diff --git a/.ci.yaml b/.ci.yaml index 181c70b00f491..022c07705186f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -89,29 +89,6 @@ targets: - testing/scenario_app/** - testing/skia_gold_client/** -# Task to run Linux linux_android_emulator_tests on AVDs running Android 33 -# instead of 34 for investigating https://github.com/flutter/flutter/issues/137947. - - name: Linux linux_android_emulator_tests_api_33 - bringup: true - enabled_branches: - - main - recipe: engine_v2/engine_v2 - properties: - config_name: linux_android_emulator_api_33 - dependencies: >- - [ - {"dependency": "goldctl", "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd"} - ] - timeout: 60 - runIf: - - .ci.yaml - - ci/builders/linux_android_emulator_api_33.json - - DEPS - - lib/ui/** - - shell/platform/android/** - - testing/scenario_app/** - - testing/skia_gold_client/** - - name: Linux builder_cache enabled_branches: - main diff --git a/ci/builders/linux_android_emulator_api_33.json b/ci/builders/linux_android_emulator_api_33.json deleted file mode 100644 index 7f02655523cdd..0000000000000 --- a/ci/builders/linux_android_emulator_api_33.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "builds": [ - { - "drone_dimensions": [ - "device_type=none", - "os=Linux", - "kvm=1", - "cores=8" - ], - "gclient_variables": { - "use_rbe": true - }, - "gn": [ - "--android", - "--android-cpu=x64", - "--no-lto", - "--rbe", - "--no-goma", - "--target-dir", - "android_debug_api33_x64" - ], - "dependencies": [ - { - "dependency": "goldctl", - "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd" - } - ], - "name": "android_debug_api33_x64", - "ninja": { - "config": "android_debug_api33_x64", - "targets": [ - "flutter/impeller/toolkit/android:unittests", - "flutter/shell/platform/android:flutter_shell_native_unittests", - "flutter/testing/scenario_app" - ] - }, - "tests": [ - { - "language": "python3", - "name": "Android Unit Tests", - "test_dependencies": [ - { - "dependency": "android_virtual_device", - "version": "android_33_google_apis_x64.textpb" - }, - { - "dependency": "avd_cipd_version", - "version": "build_id:8759428741582061553" - } - ], - "contexts": [ - "android_virtual_device" - ], - "script": "flutter/testing/run_tests.py", - "parameters": [ - "--android-variant", - "android_debug_api33_x64", - "--type", - "android" - ] - }, - { - "language": "dart", - "name": "Scenario App Integration Tests", - "test_timeout_secs": 900, - "max_attempts": 1, - "test_dependencies": [ - { - "dependency": "android_virtual_device", - "version": "android_33_google_apis_x64.textpb" - }, - { - "dependency": "avd_cipd_version", - "version": "build_id:8759428741582061553" - } - ], - "contexts": [ - "android_virtual_device" - ], - "script": "flutter/testing/scenario_app/bin/run_android_tests.dart", - "parameters": [ - "--out-dir=../out/android_debug_api33_x64" - ] - } - ] - } - ] -} From 1c08774e06af1e10ffac192995f3db587b37c808 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 28 Mar 2024 13:58:54 -0700 Subject: [PATCH 05/49] Remove `--verbose` from clang_tidy execution on CI. (#51760) Closes https://github.com/flutter/flutter/issues/145926. This was likely left on by accident (if not, we should utilize `FLUTTER_LOGS_DIR` instead of this flag). /cc @zanderso --- ci/builders/linux_clang_tidy.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci/builders/linux_clang_tidy.json b/ci/builders/linux_clang_tidy.json index b233e117d67c2..cd546bc4d2ad0 100644 --- a/ci/builders/linux_clang_tidy.json +++ b/ci/builders/linux_clang_tidy.json @@ -68,7 +68,6 @@ { "name": "test: lint host_debug", "parameters": [ - "--verbose", "--variant", "host_debug_clang_tidy", "--lint-all", @@ -98,7 +97,6 @@ { "name": "test: lint host_debug", "parameters": [ - "--verbose", "--variant", "host_debug_clang_tidy", "--lint-all", @@ -128,7 +126,6 @@ { "name": "test: lint host_debug", "parameters": [ - "--verbose", "--variant", "host_debug_clang_tidy", "--lint-all", @@ -158,7 +155,6 @@ { "name": "test: lint host_debug", "parameters": [ - "--verbose", "--variant", "host_debug_clang_tidy", "--lint-all", @@ -186,7 +182,6 @@ { "name": "test: lint android_debug_arm64", "parameters": [ - "--verbose", "--variant", "android_debug_arm64_clang_tidy", "--lint-all", From b917b24836fdfdbb34c1acdc787a23b7e324cd2b Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 28 Mar 2024 14:05:24 -0700 Subject: [PATCH 06/49] Test that `clangd --check` works at HEAD. (#50901) Closes https://github.com/flutter/flutter/issues/141641. Basically, this should verify "it's possible to use VSCode+LSC, at least in theory". I'm open to writing a test, but given it _is_ a test I'm less sure it's valuable. Feel free to push back. --- .ci.yaml | 12 ++ .clangd | 10 ++ ci/builders/linux_unopt_debug_no_rbe.json | 32 ++++++ ci/builders/mac_unopt_debug_no_rbe.json | 38 +++++++ ci/licenses_golden/licenses_flutter | 1 + tools/clangd_check/README.md | 27 +++++ tools/clangd_check/bin/main.dart | 131 ++++++++++++++++++++++ tools/clangd_check/pubspec.yaml | 68 +++++++++++ tools/pub_get_offline.py | 1 + 9 files changed, 320 insertions(+) create mode 100644 .clangd create mode 100644 ci/builders/linux_unopt_debug_no_rbe.json create mode 100644 ci/builders/mac_unopt_debug_no_rbe.json create mode 100644 tools/clangd_check/README.md create mode 100644 tools/clangd_check/bin/main.dart create mode 100644 tools/clangd_check/pubspec.yaml diff --git a/.ci.yaml b/.ci.yaml index 022c07705186f..314883c8dda7f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -277,6 +277,12 @@ targets: - ci/** - flutter_frontend_server/** + - name: Linux clangd + recipe: engine_v2/engine_v2 + bringup: true + properties: + config_name: linux_unopt_debug_no_rbe + - name: Linux linux_unopt recipe: engine_v2/engine_v2 timeout: 120 @@ -362,6 +368,12 @@ targets: drone_dimensions: - os=Mac-13 + - name: Mac clangd + recipe: engine_v2/engine_v2 + bringup: true + properties: + config_name: mac_unopt_debug_no_rbe + - name: Mac mac_unopt recipe: engine_v2/engine_v2 properties: diff --git a/.clangd b/.clangd new file mode 100644 index 0000000000000..c36b4792d750c --- /dev/null +++ b/.clangd @@ -0,0 +1,10 @@ +# Used to allow clangd to run on CI platforms as part of //tools/clangd_check. +# +# Intended to have no effect elsewhere. +# +# See also: +# - https://clangd.llvm.org/config#compileflags +# - https://github.com/clangd/clangd/issues/662 +CompileFlags: + Add: -Wno-unknown-warning-option + Remove: [-m*, -f*] diff --git a/ci/builders/linux_unopt_debug_no_rbe.json b/ci/builders/linux_unopt_debug_no_rbe.json new file mode 100644 index 0000000000000..566ece3c5ff63 --- /dev/null +++ b/ci/builders/linux_unopt_debug_no_rbe.json @@ -0,0 +1,32 @@ +{ + "_comment": [ + "This build is only used to generate compile_commands.json for clangd ", + "and should not be used for any other purpose." + ], + "builds": [ + { + "drone_dimensions": ["device_type=none", "os=Linux", "cores=32"], + "gn": [ + "--runtime-mode", + "debug", + "--unoptimized", + "--prebuilt-dart-sdk", + "--no-rbe", + "--no-goma" + ], + "name": "linux_unopt_debug_no_rbe", + "ninja": { + "config": "linux_unopt_debug_no_rbe", + "targets": ["flutter/build/dart:copy_dart_sdk"] + }, + "tests": [ + { + "language": "dart", + "name": "clangd", + "script": "flutter/tools/clangd_check/bin/main.dart", + "parameters": ["--clangd=buildtools/linux-x64/clang/bin/clangd"] + } + ] + } + ] +} diff --git a/ci/builders/mac_unopt_debug_no_rbe.json b/ci/builders/mac_unopt_debug_no_rbe.json new file mode 100644 index 0000000000000..2c8c5eddab5d0 --- /dev/null +++ b/ci/builders/mac_unopt_debug_no_rbe.json @@ -0,0 +1,38 @@ +{ + "_comment": [ + "This build is only used to generate compile_commands.json for clangd ", + "and should not be used for any other purpose." + ], + "builds": [ + { + "drone_dimensions": [ + "device_type=none", + "os=Mac-13", + "cpu=x86", + "mac_model=Macmini8,1" + ], + "gn": [ + "--runtime-mode", + "debug", + "--unoptimized", + "--prebuilt-dart-sdk", + "--no-rbe", + "--no-goma", + "--xcode-symlinks" + ], + "name": "mac_unopt_debug_no_rbe", + "ninja": { + "config": "mac_unopt_debug_no_rbe", + "targets": ["flutter/build/dart:copy_dart_sdk"] + }, + "tests": [ + { + "language": "dart", + "name": "clangd", + "script": "flutter/tools/clangd_check/bin/main.dart", + "parameters": ["--clangd=buildtools/mac-x64/clang/bin/clangd"] + } + ] + } + ] +} diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index feb7ecc75b01c..d94f8f8c48356 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -41993,6 +41993,7 @@ ORIGIN: ../../../flutter/vulkan/vulkan_utilities.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/vulkan/vulkan_window.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/vulkan/vulkan_window.h + ../../../flutter/LICENSE TYPE: LicenseType.bsd +FILE: ../../../flutter/.clangd FILE: ../../../flutter/.pylintrc FILE: ../../../flutter/assets/asset_manager.cc FILE: ../../../flutter/assets/asset_manager.h diff --git a/tools/clangd_check/README.md b/tools/clangd_check/README.md new file mode 100644 index 0000000000000..88f8c9e48faed --- /dev/null +++ b/tools/clangd_check/README.md @@ -0,0 +1,27 @@ +# `clangd_check` + +`clangd_check` is a tool to run clangd on a codebase and check for diagnostics. + +The practical use of this tool is intentionally limited; it's designed to +provide a quick way to verify that `clangd` is able to parse and analyze a +C++ codebase. + +## Usage + +```sh +dart ./tools/clangd_check/bin/main.dart +``` + +On success, and with no diagnostics, `clangd_check` will exit with status 0. + +By default, `clangd_check` will try to infer the path of `clangd`, as well as +the path to `--compile-commands-dir` based on what artifacts are present in +`$ENGINE/src/out`. + +You can also specify the path to `clangd` and `--compile-commands-dir` manually: + +```sh +dart ./tools/clangd_check/bin/main.dart \ + --clangd ../buildtools/mac-arm64/clang/bin/clangd \ + --compile-commands-dir ../out/host_Debug_unopt_arm64 +``` diff --git a/tools/clangd_check/bin/main.dart b/tools/clangd_check/bin/main.dart new file mode 100644 index 0000000000000..c97ae4a2090f6 --- /dev/null +++ b/tools/clangd_check/bin/main.dart @@ -0,0 +1,131 @@ +// 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. + +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:args/args.dart'; +import 'package:engine_repo_tools/engine_repo_tools.dart'; +import 'package:path/path.dart' as p; + +void main(List args) { + final Engine? engine = Engine.tryFindWithin(); + final ArgParser parser = ArgParser() + ..addFlag( + 'help', + abbr: 'h', + help: 'Print this usage information.', + negatable: false, + ) + ..addOption( + 'clangd', + help: 'Path to clangd. Defaults to deriving the path from compile_commands.json.', + ) + ..addOption( + 'compile-commands-dir', + help: 'Path to a directory containing compile_commands.json.', + defaultsTo: engine?.latestOutput()?.compileCommandsJson.parent.path, + ); + final ArgResults results = parser.parse(args); + if (results['help'] as bool) { + io.stdout.writeln(parser.usage); + return; + } + + final String? compileCommandsDir = results['compile-commands-dir'] as String?; + if (compileCommandsDir == null) { + io.stderr.writeln('Must provide a path to compile_commands.json'); + io.exitCode = 1; + return; + } + final io.File compileCommandsFile = io.File(p.join(compileCommandsDir, 'compile_commands.json')); + if (!compileCommandsFile.existsSync()) { + io.stderr.writeln('No compile_commands.json found in $compileCommandsDir'); + io.exitCode = 1; + return; + } + + final List compileCommands = json.decode(compileCommandsFile.readAsStringSync()) as List; + if (compileCommands.isEmpty) { + io.stderr.writeln('Unexpected: compile_commands.json is empty'); + io.exitCode = 1; + return; + } + + String? clangd = results['clangd'] as String?; + final Map entry = compileCommands.first! as Map; + final String checkFile; + if (entry case { + 'command': final String command, + 'file': final String file, + }) { + // Given a path like ../../flutter/foo.cc, we want to check foo.cc. + checkFile = p.split(file).skip(3).join(p.separator); + // On CI, the command path is different from the local path. + // Find the engine root and derive the clangd path from there. + if (clangd == null) { + // Strip the command to find the path to the engine root. + // i.e. "command": "/path/to/engine/src/... arg1 arg2 ..." + // + // This now looks like "../../flutter/buildtools/{platform}/{...}" + final String commandPath = p.dirname(command.split(' ').first); + + // Find the canonical path to the command (i.e. resolve "../" and ".") + // + // This now looks like "/path/to/engine/src/flutter/buildtools/{platform}/{...}" + final String path = p.canonicalize( + p.join(compileCommandsDir, commandPath), + ); + + // Extract which platform we're building for (e.g. linux-x64, mac-arm64, mac-x64). + final String platform = RegExp( + r'buildtools/([^/]+)/', + ).firstMatch(path)!.group(1)!; + + // Find the engine root and derive the clangd path from there. + final Engine compileCommandsEngineRoot = Engine.findWithin(path); + clangd = p.join( + // engine/src/flutter + compileCommandsEngineRoot.flutterDir.path, + // buildtools + 'buildtools', + // {platform} + platform, + // clangd + 'clang', + 'bin', + 'clangd', + ); + } + } else { + io.stderr.writeln('Unexpected: compile_commands.json has an unexpected format'); + io.stderr.writeln('First entry: ${const JsonEncoder.withIndent(' ').convert(entry)}'); + io.exitCode = 1; + return; + } + + // Run clangd. + try { + final io.ProcessResult result = io.Process.runSync(clangd, [ + '--compile-commands-dir', + compileCommandsDir, + '--check=$checkFile', + ]); + io.stdout.write(result.stdout); + io.stderr.write(result.stderr); + if ((result.stderr as String).contains('Path specified by --compile-commands-dir does not exist')) { + io.stdout.writeln('clangd_check failed: --compile-commands-dir does not exist'); + io.exitCode = 1; + } else if ((result.stderr as String).contains('Failed to resolve path')) { + io.stdout.writeln('clangd_check failed: --check file does not exist'); + io.exitCode = 1; + } else { + io.exitCode = result.exitCode; + } + } on io.ProcessException catch (e) { + io.stderr.writeln('Failed to run clangd: $e'); + io.stderr.writeln(const JsonEncoder.withIndent(' ').convert(entry)); + io.exitCode = 1; + } +} diff --git a/tools/clangd_check/pubspec.yaml b/tools/clangd_check/pubspec.yaml new file mode 100644 index 0000000000000..b82318fa62fee --- /dev/null +++ b/tools/clangd_check/pubspec.yaml @@ -0,0 +1,68 @@ +# 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. + +name: clangd_check +publish_to: none + +# Do not add any dependencies that require more than what is provided in +# //third_party/dart/pkg or //third_party/dart/third_party/pkg. +# In particular, package:test is not usable here. + +# If you do add packages here, make sure you can run `pub get --offline`, and +# check the .packages and .package_config to make sure all the paths are +# relative to this directory into //third_party/dart + +environment: + sdk: '>=3.2.0-0 <4.0.0' + +dependencies: + args: any + engine_repo_tools: any + path: any + source_span: any + +dev_dependencies: + async_helper: any + expect: any + litetest: any + process_fakes: any + smith: any + +dependency_overrides: + args: + path: ../../../third_party/dart/third_party/pkg/args + async: + path: ../../../third_party/dart/third_party/pkg/async + async_helper: + path: ../../../third_party/dart/pkg/async_helper + collection: + path: ../../../third_party/dart/third_party/pkg/collection + engine_repo_tools: + path: ../pkg/engine_repo_tools + expect: + path: ../../../third_party/dart/pkg/expect + file: + path: ../../../third_party/dart/third_party/pkg/file/packages/file + git_repo_tools: + path: ../pkg/git_repo_tools + litetest: + path: ../../testing/litetest + meta: + path: ../../../third_party/dart/pkg/meta + path: + path: ../../../third_party/dart/third_party/pkg/path + platform: + path: ../../third_party/pkg/platform + process: + path: ../../third_party/pkg/process + process_fakes: + path: ../pkg/process_fakes + process_runner: + path: ../../third_party/pkg/process_runner + smith: + path: ../../../third_party/dart/pkg/smith + source_span: + path: ../../../third_party/dart/third_party/pkg/source_span + term_glyph: + path: ../../../third_party/dart/third_party/pkg/term_glyph diff --git a/tools/pub_get_offline.py b/tools/pub_get_offline.py index 5f603b3a6f62a..f77e59d7d9577 100644 --- a/tools/pub_get_offline.py +++ b/tools/pub_get_offline.py @@ -34,6 +34,7 @@ os.path.join(ENGINE_DIR, 'tools', 'api_check'), os.path.join(ENGINE_DIR, 'tools', 'build_bucket_golden_scraper'), os.path.join(ENGINE_DIR, 'tools', 'clang_tidy'), + os.path.join(ENGINE_DIR, 'tools', 'clangd_check'), os.path.join(ENGINE_DIR, 'tools', 'compare_goldens'), os.path.join(ENGINE_DIR, 'tools', 'const_finder'), os.path.join(ENGINE_DIR, 'tools', 'dir_contents_diff'), From 8b893cb3b607ed47f35f118a6dd975d64aaa2088 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 28 Mar 2024 18:14:22 -0400 Subject: [PATCH 07/49] Roll Skia from e25b0f9006a4 to 6042ad386bcf (1 revision) (#51763) https://skia.googlesource.com/skia.git/+log/e25b0f9006a4..6042ad386bcf 2024-03-28 bungeman@google.com [fontations] Respect aliasing If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index facd5b23bba5a..221d9f319c385 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'e25b0f9006a40cdc044f8a9982a820d80d9f1fcb', + 'skia_revision': '6042ad386bcf6461660d1af7549ff6a3191ea9ff', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 33350416a2ef5..810c75fb10779 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 248fbec3c228f4aa1d6330df92c6e26b +Signature: 1ca55f2dc76427828e21f5608503d861 ==================================================================================================== LIBRARY: etc1 From b5c00a305f1a90dc3e4e520505e7338cf626b7a0 Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Thu, 28 Mar 2024 16:11:24 -0700 Subject: [PATCH 08/49] Add `et query tests` and `et test` commands (#51605) - `et query tests` enumerates all test binaries encoded in BUILD.gn files. - `et test` builds, then, runs a set of tests in parallel - Tests --- tools/engine_tool/lib/src/build_utils.dart | 12 +- .../lib/src/commands/build_command.dart | 18 +-- .../engine_tool/lib/src/commands/command.dart | 24 ++- .../lib/src/commands/command_runner.dart | 2 + .../lib/src/commands/lint_command.dart | 115 +-------------- .../lib/src/commands/query_command.dart | 56 ++++++- .../lib/src/commands/run_command.dart | 22 +-- .../lib/src/commands/test_command.dart | 81 ++++++++++ tools/engine_tool/lib/src/gn_utils.dart | 137 +++++++++++++++++ tools/engine_tool/lib/src/proc_utils.dart | 139 +++++++++++++++++- tools/engine_tool/test/fixtures.dart | 12 ++ tools/engine_tool/test/gn_utils_test.dart | 75 ++++++++++ .../engine_tool/test/query_command_test.dart | 76 ++++++---- tools/engine_tool/test/test_command_test.dart | 86 +++++++++++ tools/engine_tool/test/utils.dart | 114 ++++++++++++++ 15 files changed, 783 insertions(+), 186 deletions(-) create mode 100644 tools/engine_tool/lib/src/commands/test_command.dart create mode 100644 tools/engine_tool/lib/src/gn_utils.dart create mode 100644 tools/engine_tool/test/gn_utils_test.dart create mode 100644 tools/engine_tool/test/test_command_test.dart create mode 100644 tools/engine_tool/test/utils.dart diff --git a/tools/engine_tool/lib/src/build_utils.dart b/tools/engine_tool/lib/src/build_utils.dart index 0be0e587258d4..433f57ce9ab6c 100644 --- a/tools/engine_tool/lib/src/build_utils.dart +++ b/tools/engine_tool/lib/src/build_utils.dart @@ -66,11 +66,9 @@ void debugCheckBuilds(List builds) { } /// Build the build target in the environment. -Future runBuild( - Environment environment, - Build build, { - List extraGnArgs = const [], -}) async { +Future runBuild(Environment environment, Build build, + {List extraGnArgs = const [], + List targets = const []}) async { // If RBE config files aren't in the tree, then disable RBE. final String rbeConfigPath = p.join( environment.engine.srcDir.path, @@ -79,10 +77,11 @@ Future runBuild( 'rbe', ); final List gnArgs = [ - ...extraGnArgs, if (!io.Directory(rbeConfigPath).existsSync()) '--no-rbe', + ...extraGnArgs, ]; + // TODO(loic-sharma): Fetch dependencies if needed. final BuildRunner buildRunner = BuildRunner( platform: environment.platform, processRunner: environment.processRunner, @@ -91,6 +90,7 @@ Future runBuild( build: build, extraGnArgs: gnArgs, runTests: false, + extraNinjaArgs: targets, ); Spinner? spinner; diff --git a/tools/engine_tool/lib/src/commands/build_command.dart b/tools/engine_tool/lib/src/commands/build_command.dart index 366a831be2069..fc6a81dad54f8 100644 --- a/tools/engine_tool/lib/src/commands/build_command.dart +++ b/tools/engine_tool/lib/src/commands/build_command.dart @@ -17,25 +17,12 @@ final class BuildCommand extends CommandBase { }) { builds = runnableBuilds(environment, configs); debugCheckBuilds(builds); - argParser.addOption( - configFlag, - abbr: 'c', - defaultsTo: 'host_debug', - help: 'Specify the build config to use', - allowed: [ - for (final Build config in runnableBuilds(environment, configs)) - config.name, - ], - allowedHelp: { - for (final Build config in runnableBuilds(environment, configs)) - config.name: config.gn.join(' '), - }, - ); + addConfigOption(argParser, runnableBuilds(environment, configs)); argParser.addFlag( rbeFlag, defaultsTo: true, help: 'RBE is enabled by default when available. Use --no-rbe to ' - 'disable it.', + 'disable it.', ); } @@ -63,7 +50,6 @@ final class BuildCommand extends CommandBase { if (!useRbe) '--no-rbe', ]; - // TODO(loic-sharma): Fetch dependencies if needed. return runBuild(environment, build, extraGnArgs: extraGnArgs); } } diff --git a/tools/engine_tool/lib/src/commands/command.dart b/tools/engine_tool/lib/src/commands/command.dart index 3e61ff388e4a1..3224f7654cc56 100644 --- a/tools/engine_tool/lib/src/commands/command.dart +++ b/tools/engine_tool/lib/src/commands/command.dart @@ -2,17 +2,35 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:args/args.dart'; import 'package:args/command_runner.dart'; +import 'package:engine_build_configs/engine_build_configs.dart'; import '../environment.dart'; +import 'flags.dart'; /// The base class that all commands and subcommands should inherit from. abstract base class CommandBase extends Command { /// Constructs the base command. - CommandBase({ - required this.environment - }); + CommandBase({required this.environment}); /// The host system environment. final Environment environment; } + +/// Adds the -c (--config) option to the parser. +void addConfigOption(ArgParser parser, List builds, + {String defaultsTo = 'host_debug'}) { + parser.addOption( + configFlag, + abbr: 'c', + defaultsTo: defaultsTo, + help: 'Specify the build config to use', + allowed: [ + for (final Build config in builds) config.name, + ], + allowedHelp: { + for (final Build config in builds) config.name: config.gn.join(' '), + }, + ); +} diff --git a/tools/engine_tool/lib/src/commands/command_runner.dart b/tools/engine_tool/lib/src/commands/command_runner.dart index cf4bc92f83d54..12c1d09edb832 100644 --- a/tools/engine_tool/lib/src/commands/command_runner.dart +++ b/tools/engine_tool/lib/src/commands/command_runner.dart @@ -13,6 +13,7 @@ import 'format_command.dart'; import 'lint_command.dart'; import 'query_command.dart'; import 'run_command.dart'; +import 'test_command.dart'; const int _usageLineLength = 80; @@ -31,6 +32,7 @@ final class ToolCommandRunner extends CommandRunner { BuildCommand(environment: environment, configs: configs), RunCommand(environment: environment, configs: configs), LintCommand(environment: environment), + TestCommand(environment: environment, configs: configs), ]; commands.forEach(addCommand); diff --git a/tools/engine_tool/lib/src/commands/lint_command.dart b/tools/engine_tool/lib/src/commands/lint_command.dart index 1fa9907f0fc34..75989a4ff1c55 100644 --- a/tools/engine_tool/lib/src/commands/lint_command.dart +++ b/tools/engine_tool/lib/src/commands/lint_command.dart @@ -3,13 +3,11 @@ // found in the LICENSE file. import 'dart:io' show Directory; -import 'dart:math'; import 'package:path/path.dart' as p; import '../dart_utils.dart'; -import '../environment.dart'; -import '../logger.dart'; + import '../proc_utils.dart'; import '../worker_pool.dart'; import 'command.dart'; @@ -113,114 +111,3 @@ final class LintCommand extends CommandBase { return r ? 0 : 1; } } - -/// A WorkerPoolProgressReporter designed to work with ProcessTasks. -class ProcessTaskProgressReporter implements WorkerPoolProgressReporter { - /// Construct a new reporter. - ProcessTaskProgressReporter(this._environment); - - final Environment _environment; - Spinner? _spinner; - bool _finished = false; - int _longestName = 0; - - @override - void onRun(Set tasks) { - for (final WorkerTask task in tasks) { - _longestName = max(_longestName, task.name.length); - } - } - - @override - void onFinish() { - _finished = true; - _updateSpinner([]); - } - - List _makeProcessTaskList(WorkerPool pool) { - final List runningTasks = []; - for (final WorkerTask task in pool.running) { - if (task is! ProcessTask) { - continue; - } - runningTasks.add(task); - } - return runningTasks; - } - - @override - void onTaskStart(WorkerPool pool, WorkerTask task) { - final List running = _makeProcessTaskList(pool); - _updateSpinner(running); - } - - @override - void onTaskDone(WorkerPool pool, WorkerTask task, [Object? err]) { - final List running = _makeProcessTaskList(pool); - task as ProcessTask; - final ProcessArtifacts pa = task.processArtifacts; - final String dt = _formatDurationShort(task.runTime); - if (pa.exitCode != 0) { - final String paPath = task.processArtifactsPath; - _environment.logger.clearLine(); - _environment.logger.status( - 'FAIL: ${task.name.padLeft(_longestName)} after $dt [details in $paPath]'); - } else { - _environment.logger.clearLine(); - _environment.logger - .status('OKAY: ${task.name.padLeft(_longestName)} after $dt'); - } - _updateSpinner(running); - } - - void _updateSpinner(List tasks) { - if (_spinner != null) { - _spinner!.finish(); - _spinner = null; - } - if (_finished) { - return; - } - _environment.logger.clearLine(); - String runStatus = '['; - for (final ProcessTask pt in tasks) { - if (runStatus != '[') { - runStatus += ' '; - } - runStatus += pt.name; - } - if (tasks.isNotEmpty) { - runStatus += '...'; - } - runStatus += '] '; - _environment.logger.status('Linting $runStatus', newline: false); - _spinner = _environment.logger.startSpinner(); - } -} - -String _formatDurationShort(Duration dur) { - int micros = dur.inMicroseconds; - String r = ''; - if (micros >= Duration.microsecondsPerMinute) { - final int minutes = micros ~/ Duration.microsecondsPerMinute; - micros -= minutes * Duration.microsecondsPerMinute; - r += '${minutes}m'; - } - if (micros >= Duration.microsecondsPerSecond) { - final int seconds = micros ~/ Duration.microsecondsPerSecond; - micros -= seconds * Duration.microsecondsPerSecond; - if (r.isNotEmpty) { - r += '.'; - } - r += '${seconds}s'; - } - if (micros >= Duration.microsecondsPerMillisecond) { - final int millis = micros ~/ Duration.microsecondsPerMillisecond; - micros -= millis * Duration.microsecondsPerMillisecond; - if (r.isNotEmpty) { - r += '.'; - } - r += '${millis}ms'; - } - return r; -} diff --git a/tools/engine_tool/lib/src/commands/query_command.dart b/tools/engine_tool/lib/src/commands/query_command.dart index b70ee43ae8989..6f4c6ee367e37 100644 --- a/tools/engine_tool/lib/src/commands/query_command.dart +++ b/tools/engine_tool/lib/src/commands/query_command.dart @@ -2,8 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:io'; + import 'package:engine_build_configs/engine_build_configs.dart'; +import 'package:path/path.dart' as p; + +import '../build_utils.dart'; +import '../gn_utils.dart'; import 'command.dart'; import 'flags.dart'; @@ -42,6 +48,10 @@ final class QueryCommand extends CommandBase { environment: environment, configs: configs, )); + addSubcommand(QueryTestsCommand( + environment: environment, + configs: configs, + )); } /// Build configurations loaded from the engine from under ci/builders. @@ -55,9 +65,9 @@ final class QueryCommand extends CommandBase { 'and tests.'; } -/// The 'query builds' command. +/// The 'query builders' command. final class QueryBuildersCommand extends CommandBase { - /// Constructs the 'query build' command. + /// Constructs the 'query builders' command. QueryBuildersCommand({ required super.environment, required this.configs, @@ -120,3 +130,45 @@ final class QueryBuildersCommand extends CommandBase { return 0; } } + +/// The query tests command. +final class QueryTestsCommand extends CommandBase { + /// Constructs the 'query tests' command. + QueryTestsCommand({ + required super.environment, + required this.configs, + }) { + builds = runnableBuilds(environment, configs); + debugCheckBuilds(builds); + addConfigOption(argParser, runnableBuilds(environment, configs)); + } + + /// Build configurations loaded from the engine from under ci/builders. + final Map configs; + + /// List of compatible builds. + late final List builds; + + @override + String get name => 'tests'; + + @override + String get description => 'Provides information about test targets'; + + @override + Future run() async { + final String configName = argResults![configFlag] as String; + final Build? build = + builds.where((Build build) => build.name == configName).firstOrNull; + if (build == null) { + environment.logger.error('Could not find config $configName'); + return 1; + } + final Map targets = await findTestTargets(environment, + Directory(p.join(environment.engine.outDir.path, build.ninja.config))); + for (final TestTarget target in targets.values) { + environment.logger.status(target.label); + } + return 0; + } +} diff --git a/tools/engine_tool/lib/src/commands/run_command.dart b/tools/engine_tool/lib/src/commands/run_command.dart index 3976aef6f769f..35e5657c58941 100644 --- a/tools/engine_tool/lib/src/commands/run_command.dart +++ b/tools/engine_tool/lib/src/commands/run_command.dart @@ -21,27 +21,15 @@ final class RunCommand extends CommandBase { }) { builds = runnableBuilds(environment, configs); debugCheckBuilds(builds); - - argParser.addOption( - configFlag, - abbr: 'c', - defaultsTo: '', - help: - 'Specify the build config to use for the target build (usually auto detected)', - allowed: [ - for (final Build build in runnableBuilds(environment, configs)) - build.name, - ], - allowedHelp: { - for (final Build build in runnableBuilds(environment, configs)) - build.name: build.gn.join(' '), - }, - ); + // We default to nothing in order to automatically detect attached devices + // and select an appropriate target from them. + addConfigOption(argParser, runnableBuilds(environment, configs), + defaultsTo: ''); argParser.addFlag( rbeFlag, defaultsTo: true, help: 'RBE is enabled by default when available. Use --no-rbe to ' - 'disable it.', + 'disable it.', ); } diff --git a/tools/engine_tool/lib/src/commands/test_command.dart b/tools/engine_tool/lib/src/commands/test_command.dart new file mode 100644 index 0000000000000..7e7d82faae0ac --- /dev/null +++ b/tools/engine_tool/lib/src/commands/test_command.dart @@ -0,0 +1,81 @@ +// 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. + +import 'dart:io'; + +import 'package:engine_build_configs/engine_build_configs.dart'; +import 'package:path/path.dart' as p; + +import '../build_utils.dart'; +import '../gn_utils.dart'; +import '../proc_utils.dart'; +import '../worker_pool.dart'; +import 'command.dart'; +import 'flags.dart'; + +/// The root 'test' command. +final class TestCommand extends CommandBase { + /// Constructs the 'test' command. + TestCommand({ + required super.environment, + required Map configs, + }) { + builds = runnableBuilds(environment, configs); + debugCheckBuilds(builds); + addConfigOption(argParser, runnableBuilds(environment, configs)); + } + + /// List of compatible builds. + late final List builds; + + @override + String get name => 'test'; + + @override + String get description => 'Runs a test target' + 'et test //flutter/fml/... # Run all test targets in `//flutter/fml/`' + 'et test //flutter/fml:fml_benchmarks # Run a single test target in `//flutter/fml/`'; + + @override + Future run() async { + final String configName = argResults![configFlag] as String; + final Build? build = + builds.where((Build build) => build.name == configName).firstOrNull; + if (build == null) { + environment.logger.error('Could not find config $configName'); + return 1; + } + + final Map allTargets = await findTestTargets( + environment, + Directory(p.join(environment.engine.outDir.path, build.ninja.config))); + final Set selectedTargets = + selectTargets(argResults!.rest, allTargets); + if (selectedTargets.isEmpty) { + environment.logger.error( + 'No build targets matched ${argResults!.rest}\nRun `et query tests` to see list of targets.'); + return 1; + } + // Chop off the '//' prefix. + final List buildTargets = selectedTargets + .map((TestTarget target) => target.label.substring('//'.length)) + .toList(); + // TODO(johnmccutchan): runBuild manipulates buildTargets and adds some + // targets listed in Build. Fix this. + final int buildExitCode = + await runBuild(environment, build, targets: buildTargets); + if (buildExitCode != 0) { + return buildExitCode; + } + final WorkerPool workerPool = + WorkerPool(environment, ProcessTaskProgressReporter(environment)); + final Set tasks = {}; + for (final TestTarget target in selectedTargets) { + final List commandLine = [target.executable.path]; + tasks.add(ProcessTask( + target.label, environment, environment.engine.srcDir, commandLine)); + } + return await workerPool.run(tasks) ? 0 : 1; + } +} diff --git a/tools/engine_tool/lib/src/gn_utils.dart b/tools/engine_tool/lib/src/gn_utils.dart new file mode 100644 index 0000000000000..ace20254ebca7 --- /dev/null +++ b/tools/engine_tool/lib/src/gn_utils.dart @@ -0,0 +1,137 @@ +// 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. + +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:process_runner/process_runner.dart'; + +import 'environment.dart'; +import 'proc_utils.dart'; + +/// Canonicalized build targets start with this prefix. +const String buildTargetPrefix = '//'; + +/// A suffix to build targets that recursively selects all child build targets. +const String _buildTargetGlobSuffix = '/...'; + +/// Information about a test build target. +final class TestTarget { + /// Construct a test target. + TestTarget(this.label, this.executable); + + /// The build target label. `//flutter/fml:fml_unittests` + final String label; + + /// The executable file produced after the build target is built. + final File executable; + + @override + String toString() { + return 'target=$label executable=${executable.path}'; + } +} + +/// Returns test targets for a given build directory. +Future> findTestTargets( + Environment environment, Directory buildDir) async { + final Map r = {}; + final List getLabelsCommandLine = [ + gnBinPath(environment), + 'ls', + buildDir.path, + '--type=executable', + '--testonly=true', + '--as=label', + ]; + final List getOutputsCommandLine = [ + gnBinPath(environment), + 'ls', + buildDir.path, + '--type=executable', + '--testonly=true', + '--as=output' + ]; + + // Spawn the two processes concurrently. + final Future futureLabelsResult = + environment.processRunner.runProcess(getLabelsCommandLine, + workingDirectory: environment.engine.srcDir, failOk: true); + final Future futureOutputsResult = + environment.processRunner.runProcess(getOutputsCommandLine, + workingDirectory: environment.engine.srcDir, failOk: true); + + // Await the futures, we need both to complete so the order doesn't matter. + final ProcessRunnerResult labelsResult = await futureLabelsResult; + final ProcessRunnerResult outputsResult = await futureOutputsResult; + + // Handle any process failures. + fatalIfFailed(environment, getLabelsCommandLine, labelsResult); + fatalIfFailed(environment, getOutputsCommandLine, outputsResult); + + // Extract the labels + final String rawLabels = labelsResult.stdout; + final String rawOutputs = outputsResult.stdout; + final List labels = rawLabels.split('\n'); + final List outputs = rawOutputs.split('\n'); + if (labels.length != outputs.length) { + environment.logger.fatal( + 'gn ls output is inconsistent A and B should be the same length:\nA=$labels\nB=$outputs'); + } + // Drop the empty line at the end of the output. + if (labels.isNotEmpty) { + if (labels.last.isNotEmpty || outputs.last.isNotEmpty) { + throw AssertionError('expected last line of output to be blank.'); + } + labels.removeLast(); + outputs.removeLast(); + } + for (int i = 0; i < labels.length; i++) { + final String label = labels[i]; + final String output = outputs[i]; + if (label.isEmpty) { + throw AssertionError('expected line to not be empty.'); + } + if (output.isEmpty) { + throw AssertionError('expected line to not be empty.'); + } + r[label] = TestTarget(label, File(p.join(buildDir.path, output))); + } + return r; +} + +/// Process selectors and filter allTargets for matches. +/// +/// We support: +/// 1) Exact label matches (the '//' prefix will be stripped off). +/// 2) '/...' suffix which selects all targets that match the prefix. +Set selectTargets( + List selectors, Map allTargets) { + final Set selected = {}; + for (String selector in selectors) { + if (!selector.startsWith(buildTargetPrefix)) { + // Insert the prefix when necessary. + selector = '$buildTargetPrefix$selector'; + } + final bool recursiveMatch = selector.endsWith(_buildTargetGlobSuffix); + if (recursiveMatch) { + // Remove the /... suffix. + selector = selector.substring( + 0, selector.length - _buildTargetGlobSuffix.length); + // TODO(johnmccutchan): Accelerate this by using a trie. + for (final TestTarget target in allTargets.values) { + if (target.label.startsWith(selector)) { + selected.add(target); + } + } + } else { + for (final TestTarget target in allTargets.values) { + if (target.label == selector) { + selected.add(target); + } + } + } + } + return selected; +} diff --git a/tools/engine_tool/lib/src/proc_utils.dart b/tools/engine_tool/lib/src/proc_utils.dart index cbcc226bde6be..fa43c80c4c30d 100644 --- a/tools/engine_tool/lib/src/proc_utils.dart +++ b/tools/engine_tool/lib/src/proc_utils.dart @@ -5,12 +5,14 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:math'; import 'package:path/path.dart' as p; import 'package:process_runner/process_runner.dart'; import 'environment.dart'; import 'json_utils.dart'; +import 'logger.dart'; import 'worker_pool.dart'; /// Artifacts from an exited sub-process. @@ -20,6 +22,15 @@ final class ProcessArtifacts { this.cwd, this.commandLine, this.exitCode, this.stdout, this.stderr, {this.pid}); + /// Constructs an instance of ProcessArtifacts from a ProcessRunnerResult + /// and the spawning context. + factory ProcessArtifacts.fromResult( + Directory cwd, List commandLine, ProcessRunnerResult result) { + return ProcessArtifacts( + cwd, commandLine, result.exitCode, result.stdout, result.stderr, + pid: result.pid); + } + /// Constructs an instance of ProcessArtifacts from serialized JSON text. factory ProcessArtifacts.fromJson(String serialized) { final Map artifact = @@ -31,7 +42,9 @@ final class ProcessArtifacts { final int exitCode = intOfJson(artifact, 'exitCode', errors)!; final String stdout = stringOfJson(artifact, 'stdout', errors)!; final String stderr = stringOfJson(artifact, 'stderr', errors)!; - return ProcessArtifacts(cwd, commandLine, exitCode, stdout, stderr); + final int? pid = intOfJson(artifact, 'pid', errors); + return ProcessArtifacts(cwd, commandLine, exitCode, stdout, stderr, + pid: pid); } /// Constructs an instance of ProcessArtifacts from a file containing JSON. @@ -116,3 +129,127 @@ class ProcessTask extends WorkerTask { return _processArtifactsPath!; } } + +/// A WorkerPoolProgressReporter designed to work with ProcessTasks. +class ProcessTaskProgressReporter implements WorkerPoolProgressReporter { + /// Construct a new reporter. + ProcessTaskProgressReporter(this._environment); + + final Environment _environment; + Spinner? _spinner; + bool _finished = false; + int _longestName = 0; + int _doneCount = 0; + int _totalCount = 0; + + @override + void onRun(Set tasks) { + _totalCount = tasks.length; + for (final WorkerTask task in tasks) { + assert(task is ProcessTask); + _longestName = max(_longestName, task.name.length); + } + } + + @override + void onFinish() { + _finished = true; + _updateSpinner({}); + } + + @override + void onTaskStart(WorkerPool pool, WorkerTask task) { + _updateSpinner(pool.running); + } + + @override + void onTaskDone(WorkerPool pool, WorkerTask task, [Object? err]) { + _doneCount++; + task as ProcessTask; + final ProcessArtifacts pa = task.processArtifacts; + final String dt = _formatDurationShort(task.runTime); + if (pa.exitCode != 0) { + final String paPath = task.processArtifactsPath; + _environment.logger.clearLine(); + _environment.logger.status('FAIL: $dt ${task.name} [details in $paPath]'); + } else { + _environment.logger.clearLine(); + _environment.logger.status('OKAY: $dt ${task.name}'); + } + _updateSpinner(pool.running); + } + + void _updateSpinner(Set tasks) { + if (_spinner != null) { + _spinner!.finish(); + _spinner = null; + } + if (_finished) { + return; + } + _environment.logger.clearLine(); + final String taskName = tasks.isEmpty ? '' : tasks.first.name; + final String etc = tasks.length > 1 ? '... [${tasks.length}]' : ''; + _environment.logger.status( + 'Running $_doneCount/$_totalCount $taskName$etc ', + newline: false); + _spinner = _environment.logger.startSpinner(); + } + + String _formatDurationShort(Duration dur) { + int micros = dur.inMicroseconds; + String r = ''; + if (micros >= Duration.microsecondsPerMinute) { + final int minutes = micros ~/ Duration.microsecondsPerMinute; + micros -= minutes * Duration.microsecondsPerMinute; + r += '${minutes}m'; + } + if (micros >= Duration.microsecondsPerSecond) { + final int seconds = micros ~/ Duration.microsecondsPerSecond; + micros -= seconds * Duration.microsecondsPerSecond; + if (r.isNotEmpty) { + r += '.'; + } + r += '${seconds}s'; + } + if (micros >= Duration.microsecondsPerMillisecond) { + final int millis = micros ~/ Duration.microsecondsPerMillisecond; + micros -= millis * Duration.microsecondsPerMillisecond; + if (r.isNotEmpty) { + r += '.'; + } + r += '${millis}ms'; + } + return r.padLeft(15); + } +} + +/// If result.exitCode != 0, will call logger.fatal with relevant information +/// and terminate the program. +void fatalIfFailed(Environment environment, List commandLine, + ProcessRunnerResult result) { + if (result.exitCode == 0) { + return; + } + environment.logger.fatal( + 'Process "${commandLine.join(' ')}" failed exitCode=${result.exitCode}\n' + 'STDOUT:\n${result.stdout}' + 'STDERR:\n${result.stderr}'); +} + +/// Ensures that pathToBinary includes a '.exe' suffix on relevant platforms. +String exePath(Environment environment, String pathToBinary) { + String suffix = ''; + if (environment.platform.isWindows) { + suffix = '.exe'; + } + return '$pathToBinary$suffix'; +} + +/// Returns the path to the gn binary. +String gnBinPath(Environment environment) { + return exePath( + environment, + p.join(environment.engine.srcDir.path, 'flutter', 'third_party', 'gn', + 'gn')); +} diff --git a/tools/engine_tool/test/fixtures.dart b/tools/engine_tool/test/fixtures.dart index b450136d7ca37..16096fe0ad618 100644 --- a/tools/engine_tool/test/fixtures.dart +++ b/tools/engine_tool/test/fixtures.dart @@ -194,3 +194,15 @@ String attachedDevices() => ''' } ] '''; + +// NOTE: The final empty line is intentional. +String gnLsTestOutputs() => ''' +display_list_unittests +flow_unittests +fml_arc_unittests'''; + +// NOTE: The empty blank line is intentional. +String gnLsTestLabels() => ''' +//flutter/display_list:display_list_unittests +//flutter/flow:flow_unittests +//flutter/fml:fml_arc_unittests'''; diff --git a/tools/engine_tool/test/gn_utils_test.dart b/tools/engine_tool/test/gn_utils_test.dart new file mode 100644 index 0000000000000..e2a9846d73042 --- /dev/null +++ b/tools/engine_tool/test/gn_utils_test.dart @@ -0,0 +1,75 @@ +// 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. + +import 'dart:io' as io; + +import 'package:engine_repo_tools/engine_repo_tools.dart'; +import 'package:engine_tool/src/environment.dart'; +import 'package:engine_tool/src/gn_utils.dart'; +import 'package:litetest/litetest.dart'; + +import 'utils.dart'; + +void main() { + final Engine engine; + try { + engine = Engine.findWithin(); + } catch (e) { + io.stderr.writeln(e); + io.exitCode = 1; + return; + } + + final List cannedProcesses = [ + CannedProcess((List command) => command.contains('--as=label'), + stdout: ''' +//flutter/display_list:display_list_unittests +//flutter/flow:flow_unittests +//flutter/fml:fml_arc_unittests +'''), + CannedProcess((List command) => command.contains('--as=output'), + stdout: ''' +display_list_unittests +flow_unittests +fml_arc_unittests +''') + ]; + + test('find test targets', () async { + final TestEnvironment testEnvironment = + TestEnvironment(engine, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; + final Map testTargets = + await findTestTargets(env, engine.outDir); + expect(testTargets.length, equals(3)); + expect(testTargets['//flutter/display_list:display_list_unittests'], + notEquals(null)); + expect( + testTargets['//flutter/display_list:display_list_unittests']! + .executable + .path, + endsWith('display_list_unittests')); + }); + + test('process queue failure', () async { + final TestEnvironment testEnvironment = + TestEnvironment(engine, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; + final Map testTargets = + await findTestTargets(env, engine.outDir); + expect(selectTargets(['//...'], testTargets).length, equals(3)); + expect( + selectTargets(['//flutter/display_list'], testTargets).length, + equals(0)); + expect( + selectTargets(['//flutter/display_list/...'], testTargets) + .length, + equals(1)); + expect( + selectTargets(['//flutter/display_list:display_list_unittests'], + testTargets) + .length, + equals(1)); + }); +} diff --git a/tools/engine_tool/test/query_command_test.dart b/tools/engine_tool/test/query_command_test.dart index 4abed0318507c..b570ad2e28dac 100644 --- a/tools/engine_tool/test/query_command_test.dart +++ b/tools/engine_tool/test/query_command_test.dart @@ -10,14 +10,11 @@ import 'package:engine_build_configs/engine_build_configs.dart'; import 'package:engine_repo_tools/engine_repo_tools.dart'; import 'package:engine_tool/src/commands/command_runner.dart'; import 'package:engine_tool/src/environment.dart'; -import 'package:engine_tool/src/logger.dart'; import 'package:litetest/litetest.dart'; import 'package:logging/logging.dart' as log; -import 'package:platform/platform.dart'; -import 'package:process_fakes/process_fakes.dart'; -import 'package:process_runner/process_runner.dart'; import 'fixtures.dart' as fixtures; +import 'utils.dart'; void main() { final Engine engine; @@ -54,27 +51,29 @@ void main() { 'win_test_config': winTestConfig, }; - Environment linuxEnv(Logger logger) { - return Environment( - abi: ffi.Abi.linuxX64, - engine: engine, - platform: FakePlatform( - operatingSystem: Platform.linux, - resolvedExecutable: io.Platform.resolvedExecutable), - processRunner: ProcessRunner( - processManager: FakeProcessManager(), - ), - logger: logger, - ); - } - List stringsFromLogs(List logs) { return logs.map((log.LogRecord r) => r.message).toList(); } + final List cannedProcesses = [ + CannedProcess((List command) => command.contains('--as=label'), + stdout: ''' +//flutter/display_list:display_list_unittests +//flutter/flow:flow_unittests +//flutter/fml:fml_arc_unittests +'''), + CannedProcess((List command) => command.contains('--as=output'), + stdout: ''' +display_list_unittests +flow_unittests +fml_arc_unittests +''') + ]; + test('query command returns builds for the host platform.', () async { - final Logger logger = Logger.test(); - final Environment env = linuxEnv(logger); + final TestEnvironment testEnvironment = TestEnvironment(engine, + abi: ffi.Abi.linuxX64, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; final ToolCommandRunner runner = ToolCommandRunner( environment: env, configs: configs, @@ -85,7 +84,7 @@ void main() { ]); expect(result, equals(0)); expect( - stringsFromLogs(logger.testLogs), + stringsFromLogs(env.logger.testLogs), equals([ 'Add --verbose to see detailed information about each builder\n', '\n', @@ -105,8 +104,9 @@ void main() { test('query command with --builder returns only from the named builder.', () async { - final Logger logger = Logger.test(); - final Environment env = linuxEnv(logger); + final TestEnvironment testEnvironment = TestEnvironment(engine, + abi: ffi.Abi.linuxX64, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; final ToolCommandRunner runner = ToolCommandRunner( environment: env, configs: configs, @@ -119,7 +119,7 @@ void main() { ]); expect(result, equals(0)); expect( - stringsFromLogs(logger.testLogs), + stringsFromLogs(env.logger.testLogs), equals([ 'Add --verbose to see detailed information about each builder\n', '\n', @@ -132,8 +132,9 @@ void main() { }); test('query command with --all returns all builds.', () async { - final Logger logger = Logger.test(); - final Environment env = linuxEnv(logger); + final TestEnvironment testEnvironment = TestEnvironment(engine, + abi: ffi.Abi.linuxX64, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; final ToolCommandRunner runner = ToolCommandRunner( environment: env, configs: configs, @@ -145,8 +146,29 @@ void main() { ]); expect(result, equals(0)); expect( - logger.testLogs.length, + env.logger.testLogs.length, equals(30), ); }); + + test('query tests', () async { + final TestEnvironment testEnvironment = TestEnvironment(engine, + abi: ffi.Abi.linuxX64, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; + final ToolCommandRunner runner = ToolCommandRunner( + environment: env, + configs: configs, + ); + final int result = await runner.run([ + 'query', + 'tests', + ]); + expect(result, equals(0)); + expect( + env.logger.testLogs.length, + equals(3), + ); + expect(env.logger.testLogs[0].message, + startsWith('//flutter/display_list:display_list_unittests')); + }); } diff --git a/tools/engine_tool/test/test_command_test.dart b/tools/engine_tool/test/test_command_test.dart new file mode 100644 index 0000000000000..d7629cedbeb79 --- /dev/null +++ b/tools/engine_tool/test/test_command_test.dart @@ -0,0 +1,86 @@ +// 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. + +import 'dart:convert' as convert; +import 'dart:ffi' as ffi show Abi; +import 'dart:io' as io; + +import 'package:engine_build_configs/engine_build_configs.dart'; +import 'package:engine_repo_tools/engine_repo_tools.dart'; +import 'package:engine_tool/src/commands/command_runner.dart'; +import 'package:engine_tool/src/environment.dart'; +import 'package:litetest/litetest.dart'; + +import 'fixtures.dart' as fixtures; +import 'utils.dart'; + +void main() { + final Engine engine; + try { + engine = Engine.findWithin(); + } catch (e) { + io.stderr.writeln(e); + io.exitCode = 1; + return; + } + + final BuilderConfig linuxTestConfig = BuilderConfig.fromJson( + path: 'ci/builders/linux_test_config.json', + map: convert.jsonDecode(fixtures.testConfig('Linux')) + as Map, + ); + + final BuilderConfig macTestConfig = BuilderConfig.fromJson( + path: 'ci/builders/mac_test_config.json', + map: convert.jsonDecode(fixtures.testConfig('Mac-12')) + as Map, + ); + + final BuilderConfig winTestConfig = BuilderConfig.fromJson( + path: 'ci/builders/win_test_config.json', + map: convert.jsonDecode(fixtures.testConfig('Windows-11')) + as Map, + ); + + final Map configs = { + 'linux_test_config': linuxTestConfig, + 'linux_test_config2': linuxTestConfig, + 'mac_test_config': macTestConfig, + 'win_test_config': winTestConfig, + }; + + final List cannedProcesses = [ + CannedProcess((List command) => command.contains('--as=label'), + stdout: ''' +//flutter/display_list:display_list_unittests +//flutter/flow:flow_unittests +//flutter/fml:fml_arc_unittests +'''), + CannedProcess((List command) => command.contains('--as=output'), + stdout: ''' +display_list_unittests +flow_unittests +fml_arc_unittests +''') + ]; + + test('test command executes test', () async { + final TestEnvironment testEnvironment = TestEnvironment(engine, + abi: ffi.Abi.linuxX64, cannedProcesses: cannedProcesses); + final Environment env = testEnvironment.environment; + final ToolCommandRunner runner = ToolCommandRunner( + environment: env, + configs: configs, + ); + final int result = await runner.run([ + 'test', + '//flutter/display_list:display_list_unittests', + ]); + expect(result, equals(0)); + expect(testEnvironment.processHistory.length, greaterThan(3)); + final int offset = testEnvironment.processHistory.length - 1; + expect(testEnvironment.processHistory[offset].command[0], + endsWith('display_list_unittests')); + }); +} diff --git a/tools/engine_tool/test/utils.dart b/tools/engine_tool/test/utils.dart new file mode 100644 index 0000000000000..02abc466e10f2 --- /dev/null +++ b/tools/engine_tool/test/utils.dart @@ -0,0 +1,114 @@ +// 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. + +import 'dart:ffi' as ffi show Abi; +import 'dart:io' as io; + +import 'package:engine_repo_tools/engine_repo_tools.dart'; +import 'package:engine_tool/src/environment.dart'; +import 'package:engine_tool/src/logger.dart'; +import 'package:platform/platform.dart'; +import 'package:process_fakes/process_fakes.dart'; +import 'package:process_runner/process_runner.dart'; + +/// Each CannedProcess has a command matcher and the result of an executed +/// process. The matcher is used to determine when to use a registered +/// CannedProcess. +class CannedProcess { + CannedProcess( + this.commandMatcher, { + int exitCode = 0, + String stdout = '', + String stderr = '', + }) : _exitCode = exitCode, + _stdout = stdout, + _stderr = stderr; + + final bool Function(List command) commandMatcher; + final int _exitCode; + final String _stdout; + final String _stderr; + + FakeProcess get fakeProcess { + return FakeProcess(exitCode: _exitCode, stdout: _stdout, stderr: _stderr); + } +} + +/// ExecutedProcess includes the command and the result. +class ExecutedProcess { + ExecutedProcess(this.command, this.result); + final List command; + final FakeProcess result; + + @override + String toString() { + return command.join(' '); + } +} + +/// TestEnvironment includes an Environment with some test-specific extras. +class TestEnvironment { + TestEnvironment( + Engine engine, { + Logger? logger, + ffi.Abi abi = ffi.Abi.macosArm64, + this.cannedProcesses = const [], + }) { + logger ??= Logger.test(); + environment = Environment( + abi: abi, + engine: engine, + platform: FakePlatform( + operatingSystem: _operatingSystemForAbi(abi), + resolvedExecutable: io.Platform.resolvedExecutable), + processRunner: ProcessRunner( + processManager: FakeProcessManager(onStart: (List command) { + final FakeProcess processResult = + _getCannedResult(command, cannedProcesses); + processHistory.add(ExecutedProcess(command, processResult)); + return processResult; + }, onRun: (List command) { + throw UnimplementedError('onRun'); + })), + logger: logger, + ); + } + + /// Environment. + late final Environment environment; + + /// List of CannedProcesses that are registered in this environment. + final List cannedProcesses; + + /// A history of all executed processes. + final List processHistory = []; +} + +String _operatingSystemForAbi(ffi.Abi abi) { + switch (abi) { + case ffi.Abi.linuxArm: + case ffi.Abi.linuxArm64: + case ffi.Abi.linuxIA32: + case ffi.Abi.linuxX64: + case ffi.Abi.linuxRiscv32: + case ffi.Abi.linuxRiscv64: + return Platform.linux; + case ffi.Abi.macosArm64: + case ffi.Abi.macosX64: + return Platform.macOS; + default: + throw UnimplementedError('Unhandled abi=$abi'); + } +} + +FakeProcess _getCannedResult( + List command, List cannedProcesses) { + for (final CannedProcess cp in cannedProcesses) { + final bool matched = cp.commandMatcher(command); + if (matched) { + return cp.fakeProcess; + } + } + return FakeProcess(); +} From 68aa9ba386e1f8a6f1e71348ad8075e3126564a0 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 28 Mar 2024 16:32:57 -0700 Subject: [PATCH 09/49] [Impeller] dont clamp mipmap level to 0 with Vulkan textures. (#51761) Mipmaps are not working at all right now with Vulkan. Opening without fix so we see goldens changing. --- impeller/aiks/aiks_unittests.cc | 51 +++++++++++++++++++ .../renderer/backend/vulkan/sampler_vk.cc | 1 + testing/impeller_golden_tests_output.txt | 3 ++ 3 files changed, 55 insertions(+) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 39ad0e7fed709..ee375d67628a9 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -3528,6 +3528,57 @@ TEST_P(AiksTest, CanRenderClippedBackdropFilter) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, MipmapGenerationWorksCorrectly) { + TextureDescriptor texture_descriptor; + texture_descriptor.size = ISize{1024, 1024}; + texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.mip_count = texture_descriptor.size.MipCount(); + + std::vector bytes(4194304); + bool alternate = false; + for (auto i = 0u; i < 4194304; i += 4) { + if (alternate) { + bytes[i] = 255; + bytes[i + 1] = 0; + bytes[i + 2] = 0; + bytes[i + 3] = 255; + } else { + bytes[i] = 0; + bytes[i + 1] = 255; + bytes[i + 2] = 0; + bytes[i + 3] = 255; + } + alternate = !alternate; + } + + ASSERT_EQ(texture_descriptor.GetByteSizeOfBaseMipLevel(), bytes.size()); + auto mapping = std::make_shared( + bytes.data(), // data + texture_descriptor.GetByteSizeOfBaseMipLevel() // size + ); + auto texture = + GetContext()->GetResourceAllocator()->CreateTexture(texture_descriptor); + + ASSERT_TRUE(!!texture); + ASSERT_TRUE(texture->SetContents(mapping)); + + auto command_buffer = GetContext()->CreateCommandBuffer(); + auto blit_pass = command_buffer->CreateBlitPass(); + + blit_pass->GenerateMipmap(texture); + EXPECT_TRUE(blit_pass->EncodeCommands(GetContext()->GetResourceAllocator())); + EXPECT_TRUE(GetContext()->GetCommandQueue()->Submit({command_buffer}).ok()); + + auto image = std::make_shared(texture); + + Canvas canvas; + canvas.DrawImageRect(image, Rect::MakeSize(texture->GetSize()), + Rect::MakeLTRB(0, 0, 100, 100), {}); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc index 175507d1ab9bf..2e0946302d5cf 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -37,6 +37,7 @@ static vk::UniqueSampler CreateSampler( sampler_info.addressModeW = address_mode_w; sampler_info.borderColor = vk::BorderColor::eFloatTransparentBlack; sampler_info.mipmapMode = mip_map; + sampler_info.maxLod = VK_LOD_CLAMP_NONE; if (yuv_conversion && yuv_conversion->IsValid()) { sampler_chain.get().conversion = diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index ae8814380b1f8..47b290d6c968b 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -593,6 +593,9 @@ impeller_Play_AiksTest_MatrixImageFilterMagnify_Vulkan.png impeller_Play_AiksTest_MatrixSaveLayerFilter_Metal.png impeller_Play_AiksTest_MatrixSaveLayerFilter_OpenGLES.png impeller_Play_AiksTest_MatrixSaveLayerFilter_Vulkan.png +impeller_Play_AiksTest_MipmapGenerationWorksCorrectly_Metal.png +impeller_Play_AiksTest_MipmapGenerationWorksCorrectly_OpenGLES.png +impeller_Play_AiksTest_MipmapGenerationWorksCorrectly_Vulkan.png impeller_Play_AiksTest_PaintBlendModeIsRespected_Metal.png impeller_Play_AiksTest_PaintBlendModeIsRespected_OpenGLES.png impeller_Play_AiksTest_PaintBlendModeIsRespected_Vulkan.png From c1d6a8e3a9c27da3b93f3e1dac6df862a7d033c4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 28 Mar 2024 16:57:21 -0700 Subject: [PATCH 10/49] [macOS] Group per-view information in `FlutterCompositor` into a class (#51738) This PR groups per-view information in `FlutterCompositor` into a private class, `ViewPresenter`. This makes it easier to manage per-view data and write view operations. Part of https://github.com/flutter/flutter/issues/145874. Currently, view presenters are never removed once created, since the macOS runner doesn't support removing views. This will be added in the future. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../framework/Source/FlutterCompositor.h | 45 ++++++++++++------- .../framework/Source/FlutterCompositor.mm | 37 ++++++++++----- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h index aad527a3785df..8d2e5c6b33ed8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h @@ -7,6 +7,7 @@ #include #include +#include #include "flutter/fml/macros.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h" @@ -34,9 +35,9 @@ class FlutterCompositor { // The view_provider is used to query FlutterViews from view IDs, // which are used for presenting and creating backing stores. // It must not be null, and is typically FlutterViewEngineProvider. - explicit FlutterCompositor(id view_provider, - FlutterTimeConverter* time_converter, - FlutterPlatformViewController* platform_views_controller); + FlutterCompositor(id view_provider, + FlutterTimeConverter* time_converter, + FlutterPlatformViewController* platform_views_controller); ~FlutterCompositor() = default; @@ -56,19 +57,34 @@ class FlutterCompositor { FlutterBackingStore* backing_store_out); // Presents the FlutterLayers by updating the FlutterView specified by - // `view_id` using the layer content. Sets frame_started_ to false. + // `view_id` using the layer content. bool Present(FlutterViewId view_id, const FlutterLayer** layers, size_t layers_count); private: - void PresentPlatformViews(FlutterView* default_base_view, - const std::vector& platform_views_layers); - - // Presents the platform view layer represented by `layer`. `layer_index` is - // used to position the layer in the z-axis. If the layer does not have a - // superview, it will become subview of `default_base_view`. - FlutterMutatorView* PresentPlatformView(FlutterView* default_base_view, - const PlatformViewLayer& layer, - size_t index); + // A class that contains the information for a view to be presented. + class ViewPresenter { + public: + ViewPresenter(); + + void PresentPlatformViews(FlutterView* default_base_view, + const std::vector& platform_views, + const FlutterPlatformViewController* platform_views_controller); + + private: + // Platform view to FlutterMutatorView that contains it. + NSMapTable* mutator_views_; + + // Presents the platform view layer represented by `layer`. `layer_index` is + // used to position the layer in the z-axis. If the layer does not have a + // superview, it will become subview of `default_base_view`. + FlutterMutatorView* PresentPlatformView( + FlutterView* default_base_view, + const PlatformViewLayer& layer, + size_t layer_position, + const FlutterPlatformViewController* platform_views_controller); + + FML_DISALLOW_COPY_AND_ASSIGN(ViewPresenter); + }; // Where the compositor can query FlutterViews. Must not be null. id const view_provider_; @@ -79,8 +95,7 @@ class FlutterCompositor { // The controller used to manage creation and deletion of platform views. const FlutterPlatformViewController* platform_view_controller_; - // Platform view to FlutterMutatorView that contains it. - NSMapTable* mutator_views_; + std::unordered_map presenters_; FML_DISALLOW_COPY_AND_ASSIGN(FlutterCompositor); }; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index 890a4c0cfca3b..e7749ca0e539b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -27,8 +27,7 @@ FlutterPlatformViewController* platform_view_controller) : view_provider_(view_provider), time_converter_(time_converter), - platform_view_controller_(platform_view_controller), - mutator_views_([NSMapTable strongToStrongObjectsMapTable]) { + platform_view_controller_(platform_view_controller) { FML_CHECK(view_provider != nullptr) << "view_provider cannot be nullptr"; } @@ -55,6 +54,10 @@ bool FlutterCompositor::Present(FlutterViewId view_id, const FlutterLayer** layers, size_t layers_count) { + // TODO(dkwingsmt): The macOS embedder only supports rendering to the implicit + // view for now. As it supports adding more views, this assertion should be + // lifted. https://github.com/flutter/flutter/issues/142845 + FML_DCHECK(view_id == kFlutterImplicitViewId); FlutterView* view = [view_provider_ viewForId:view_id]; if (!view) { return false; @@ -98,15 +101,22 @@ [view.surfaceManager presentSurfaces:surfaces atTime:presentation_time notify:^{ - PresentPlatformViews(view, *platform_views_layers); + // Gets a presenter or create a new one for the view. + ViewPresenter& presenter = presenters_[view_id]; + presenter.PresentPlatformViews(view, *platform_views_layers, + platform_view_controller_); }]; return true; } -void FlutterCompositor::PresentPlatformViews( +FlutterCompositor::ViewPresenter::ViewPresenter() + : mutator_views_([NSMapTable strongToStrongObjectsMapTable]) {} + +void FlutterCompositor::ViewPresenter::PresentPlatformViews( FlutterView* default_base_view, - const std::vector& platform_views) { + const std::vector& platform_views, + const FlutterPlatformViewController* platform_view_controller) { FML_DCHECK([[NSThread currentThread] isMainThread]) << "Must be on the main thread to present platform views"; @@ -114,8 +124,9 @@ NSMutableArray* present_mutators = [NSMutableArray array]; for (const auto& platform_view : platform_views) { - [present_mutators addObject:PresentPlatformView(default_base_view, platform_view.first, - platform_view.second)]; + FlutterMutatorView* container = PresentPlatformView( + default_base_view, platform_view.first, platform_view.second, platform_view_controller); + [present_mutators addObject:container]; } NSMutableArray* obsolete_mutators = @@ -127,17 +138,19 @@ [mutator removeFromSuperview]; } - [platform_view_controller_ disposePlatformViews]; + [platform_view_controller disposePlatformViews]; } -FlutterMutatorView* FlutterCompositor::PresentPlatformView(FlutterView* default_base_view, - const PlatformViewLayer& layer, - size_t index) { +FlutterMutatorView* FlutterCompositor::ViewPresenter::PresentPlatformView( + FlutterView* default_base_view, + const PlatformViewLayer& layer, + size_t index, + const FlutterPlatformViewController* platform_view_controller) { FML_DCHECK([[NSThread currentThread] isMainThread]) << "Must be on the main thread to present platform views"; int64_t platform_view_id = layer.identifier(); - NSView* platform_view = [platform_view_controller_ platformViewWithID:platform_view_id]; + NSView* platform_view = [platform_view_controller platformViewWithID:platform_view_id]; FML_DCHECK(platform_view) << "Platform view not found for id: " << platform_view_id; From 8f0a2ee0e5b286df89c0182a41da3b272e2c1956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:14:10 -0700 Subject: [PATCH 11/49] [Windows] Don't always stop engine on view destruction (#51681) Currently destroying a view also shuts down the engine. This makes sense as in single-view world where the view also always owns the engine. However, in a multi-view world the views will share the engine. Destroying one view shouldn't necessarily shut down the engine unless that view owns the engine. Part of https://github.com/flutter/flutter/issues/142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- ci/licenses_golden/licenses_flutter | 2 ++ shell/platform/windows/BUILD.gn | 1 + shell/platform/windows/flutter_windows.cc | 1 + .../windows/flutter_windows_engine.cc | 18 +++++++++++ .../platform/windows/flutter_windows_engine.h | 3 ++ .../windows/flutter_windows_unittests.cc | 3 ++ .../platform/windows/flutter_windows_view.cc | 4 --- .../flutter_windows_view_controller.cc | 30 +++++++++++++++++++ .../windows/flutter_windows_view_controller.h | 14 +++++++-- .../windows/flutter_windows_view_unittests.cc | 17 ++++++----- 10 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 shell/platform/windows/flutter_windows_view_controller.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d94f8f8c48356..e040b28546e07 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -41822,6 +41822,7 @@ ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_texture_registra ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_view.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_view.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_view_controller.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/flutter_windows_view_controller.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/keyboard_handler_base.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/windows/keyboard_key_channel_handler.cc + ../../../flutter/LICENSE @@ -44730,6 +44731,7 @@ FILE: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar. FILE: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar.h FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h +FILE: ../../../flutter/shell/platform/windows/flutter_windows_view_controller.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view_controller.h FILE: ../../../flutter/shell/platform/windows/keyboard_handler_base.h FILE: ../../../flutter/shell/platform/windows/keyboard_key_channel_handler.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index bed6b8f8d7a5a..e80662e592a72 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -87,6 +87,7 @@ source_set("flutter_windows_source") { "flutter_windows_texture_registrar.h", "flutter_windows_view.cc", "flutter_windows_view.h", + "flutter_windows_view_controller.cc", "flutter_windows_view_controller.h", "keyboard_handler_base.h", "keyboard_key_channel_handler.cc", diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 874b97d537c22..d25d3f961dc5c 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -130,6 +130,7 @@ FlutterDesktopViewControllerRef FlutterDesktopEngineCreateViewController( void FlutterDesktopViewControllerDestroy(FlutterDesktopViewControllerRef ref) { auto controller = ViewControllerFromHandle(ref); + controller->Destroy(); delete controller; } diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 988e1f47954c6..4261cd08496f3 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -502,6 +502,24 @@ std::unique_ptr FlutterWindowsEngine::CreateView( return std::move(view); } +void FlutterWindowsEngine::RemoveView(FlutterViewId view_id) { + FML_DCHECK(running()); + FML_DCHECK(views_.find(view_id) != views_.end()); + + if (view_id == kImplicitViewId) { + // The engine and framework assume the implicit view always exists. + // Attempts to render to the implicit view will be ignored. + views_.erase(view_id); + return; + } + + // TODO(loicsharma): Remove the view from the engine using the + // `FlutterEngineRemoveView` embedder API. Windows does not + // support views other than the implicit view yet. + // https://github.com/flutter/flutter/issues/144810 + FML_UNREACHABLE(); +} + void FlutterWindowsEngine::OnVsync(intptr_t baton) { std::chrono::nanoseconds current_time = std::chrono::nanoseconds(embedder_api_.GetCurrentTime()); diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 018dc82a3c7c3..40f3cc058ef51 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -124,6 +124,9 @@ class FlutterWindowsEngine { std::unique_ptr CreateView( std::unique_ptr window); + // Remove a view. The engine will no longer render into it. + virtual void RemoveView(FlutterViewId view_id); + // Get a view that displays this engine's content. // // Returns null if the view does not exist. diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 37fbbcabd5c24..9a7b963303e45 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -139,6 +139,9 @@ TEST_F(WindowsTest, EngineCanTransitionToHeadless) { // The engine is back in headless mode now. ASSERT_NE(engine, nullptr); + + auto engine_ptr = reinterpret_cast(engine.get()); + ASSERT_TRUE(engine_ptr->running()); } // Verify that accessibility features are initialized when a view is created. diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index f8a87c825979f..815cbaa3bb4f8 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -105,10 +105,6 @@ FlutterWindowsView::~FlutterWindowsView() { // Notify the engine the view's child window will no longer be visible. engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide); - // The engine renders into the view's surface. The engine must be - // shutdown before the view's resources can be destroyed. - engine_->Stop(); - DestroyRenderSurface(); } diff --git a/shell/platform/windows/flutter_windows_view_controller.cc b/shell/platform/windows/flutter_windows_view_controller.cc new file mode 100644 index 0000000000000..d89d3baa59a55 --- /dev/null +++ b/shell/platform/windows/flutter_windows_view_controller.cc @@ -0,0 +1,30 @@ +// 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 "flutter/shell/platform/windows/flutter_windows_view_controller.h" + +namespace flutter { + +FlutterWindowsViewController::~FlutterWindowsViewController() { + Destroy(); +} + +void FlutterWindowsViewController::Destroy() { + if (!view_) { + return; + } + + // Prevent the engine from rendering into this view. + if (view_->GetEngine()->running()) { + auto view_id = view_->view_id(); + + view_->GetEngine()->RemoveView(view_id); + } + + // Destroy the view, followed by the engine if it is owned by this controller. + view_.reset(); + engine_.reset(); +} + +} // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view_controller.h b/shell/platform/windows/flutter_windows_view_controller.h index 10175fc9546ba..2aca77cf38e78 100644 --- a/shell/platform/windows/flutter_windows_view_controller.h +++ b/shell/platform/windows/flutter_windows_view_controller.h @@ -7,8 +7,9 @@ #include -#include "flutter_windows_engine.h" -#include "flutter_windows_view.h" +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/windows/flutter_windows_engine.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" namespace flutter { @@ -19,6 +20,13 @@ class FlutterWindowsViewController { std::unique_ptr view) : engine_(std::move(engine)), view_(std::move(view)) {} + ~FlutterWindowsViewController(); + + // Destroy this view controller and its view. + // + // If this view controller owns the engine, the engine is also destroyed. + void Destroy(); + FlutterWindowsEngine* engine() { return view_->GetEngine(); } FlutterWindowsView* view() { return view_.get(); } @@ -36,6 +44,8 @@ class FlutterWindowsViewController { std::unique_ptr engine_; std::unique_ptr view_; + + FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsViewController); }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index a11e06f37ce09..b4bb9a4789d90 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -18,6 +18,7 @@ #include "flutter/shell/platform/windows/flutter_window.h" #include "flutter/shell/platform/windows/flutter_windows_engine.h" #include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h" +#include "flutter/shell/platform/windows/flutter_windows_view_controller.h" #include "flutter/shell/platform/windows/testing/egl/mock_context.h" #include "flutter/shell/platform/windows/testing/egl/mock_manager.h" #include "flutter/shell/platform/windows/testing/egl/mock_window_surface.h" @@ -121,6 +122,7 @@ class MockFlutterWindowsEngine : public FlutterWindowsEngine { MOCK_METHOD(bool, running, (), (const)); MOCK_METHOD(bool, Stop, (), ()); + MOCK_METHOD(void, RemoveView, (FlutterViewId view_id), ()); MOCK_METHOD(bool, PostRasterThreadTask, (fml::closure), (const)); private: @@ -241,6 +243,8 @@ TEST(FlutterWindowsViewTest, Shutdown) { std::make_unique>(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); + + auto engine_ptr = engine.get(); auto surface_ptr = surface.get(); EngineModifier modifier{engine.get()}; @@ -250,12 +254,16 @@ TEST(FlutterWindowsViewTest, Shutdown) { std::unique_ptr view = engine->CreateView(std::move(window_binding_handler)); + auto view_id = view->view_id(); ViewModifier view_modifier{view.get()}; view_modifier.SetSurface(std::move(surface)); - // The engine must be stopped before the surface can be destroyed. + FlutterWindowsViewController controller{std::move(engine), std::move(view)}; + + // The view must be removed before the surface can be destroyed. InSequence s; - EXPECT_CALL(*engine.get(), Stop).Times(1); + EXPECT_CALL(*engine_ptr, running).WillOnce(Return(true)); + EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); } } @@ -1392,7 +1400,6 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) { EXPECT_CALL(*surface_ptr, SetVSyncEnabled(false)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); - EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1430,7 +1437,6 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) { EXPECT_CALL(*surface_ptr, SetVSyncEnabled(true)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); - EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1471,7 +1477,6 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(false)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); - EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1514,7 +1519,6 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(true)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); - EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1563,7 +1567,6 @@ TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) { EXPECT_CALL(*surface_ptr, SetVSyncEnabled(false)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); - EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier engine_modifier{engine.get()}; From b77fc96415bdda461dc3e2751d69d9adbf1b79c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:14:12 -0700 Subject: [PATCH 12/49] [Windows] Move keyboard initialization (#51758) Previously the keyboard was initialized after the view is created. This used to be necessary as the keyboard & text input plugins were strongly tied to a view (and would crash in headless modes). This is no longer necessary, and the keyboard can now be initialized normally as part of the engine initialization. Part of https://github.com/flutter/flutter/issues/142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- shell/platform/windows/fixtures/main.dart | 41 +++++++++++++++++++ .../windows/flutter_windows_engine.cc | 11 ++--- .../windows/flutter_windows_unittests.cc | 38 +++++++++++++++++ 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart index 5f3d61c9e0a26..9c6ae19a38dc9 100644 --- a/shell/platform/windows/fixtures/main.dart +++ b/shell/platform/windows/fixtures/main.dart @@ -231,6 +231,47 @@ void sendCreatePlatformViewMethod() async { await completed.future; } +@pragma('vm:entry-point') +void sendGetKeyboardState() async { + // The keyboard method channel uses the standard method codec. + // See https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/services/message_codecs.dart#L262 + // for the implementation of the encoding and magic number identifiers. + const int valueNull = 0; + const int valueString = 7; + const int valueMap = 13; + + const String method = 'getKeyboardState'; + final List data = [ + // Method name + valueString, method.length, ...utf8.encode(method), + // Method arguments: null + valueNull, 2, + ]; + + final Completer completer = Completer(); + final ByteData bytes = ByteData.sublistView(Uint8List.fromList(data)); + ui.PlatformDispatcher.instance.sendPlatformMessage('flutter/keyboard', bytes, (ByteData? response) { + // For magic numbers for decoding a reply envelope, see: + // https://github.com/flutter/flutter/blob/67271f69f7f88a4edba6d8023099e3bd27a072d2/packages/flutter/lib/src/services/message_codecs.dart#L577-L587 + const int replyEnvelopeSuccess = 0; + + // Ensure the response is a success containing a map of keyboard states. + if (response == null) { + signalStringValue('Unexpected null response'); + } else if (response.lengthInBytes < 2) { + signalStringValue('Unexpected response length of ${response.lengthInBytes} bytes'); + } else if (response.getUint8(0) != replyEnvelopeSuccess) { + signalStringValue('Unexpected response envelope status: ${response.getUint8(0)}'); + } else if (response.getUint8(1) != valueMap) { + signalStringValue('Unexpected response value magic number: ${response.getUint8(1)}'); + } else { + signalStringValue('Success'); + } + completer.complete(); + }); + await completer.future; +} + @pragma('vm:entry-point') void customEntrypoint() {} diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 4261cd08496f3..1969f4ebc22bd 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -473,6 +473,8 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { settings_plugin_->StartWatching(); settings_plugin_->SendSettings(); + InitializeKeyboard(); + return true; } @@ -497,7 +499,6 @@ std::unique_ptr FlutterWindowsEngine::CreateView( kImplicitViewId, this, std::move(window), windows_proc_table_); views_[kImplicitViewId] = view.get(); - InitializeKeyboard(); return std::move(view); } @@ -693,10 +694,6 @@ void FlutterWindowsEngine::SendSystemLocales() { } void FlutterWindowsEngine::InitializeKeyboard() { - if (views_.empty()) { - FML_LOG(ERROR) << "Cannot initialize keyboard on Windows headless mode."; - } - auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState; KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan = @@ -791,9 +788,7 @@ void FlutterWindowsEngine::UpdateSemanticsEnabled(bool enabled) { void FlutterWindowsEngine::OnPreEngineRestart() { // Reset the keyboard's state on hot restart. - if (!views_.empty()) { - InitializeKeyboard(); - } + InitializeKeyboard(); } std::string FlutterWindowsEngine::GetExecutableName() const { diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 9a7b963303e45..d8155d4e18d81 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -480,5 +480,43 @@ TEST_F(WindowsTest, Lifecycle) { /* bRepaint*/ false); } +TEST_F(WindowsTest, GetKeyboardStateHeadless) { + // Run the test on its own thread so that it can pump its event loop while + // this thread waits. + fml::AutoResetWaitableEvent latch; + auto platform_task_runner = CreateNewThread("test_platform_thread"); + platform_task_runner->PostTask([&]() { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("sendGetKeyboardState"); + + bool done = false; + context.AddNativeFunction( + "SignalStringValue", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + auto handle = Dart_GetNativeArgument(args, 0); + ASSERT_FALSE(Dart_IsError(handle)); + auto value = tonic::DartConverter::FromDart(handle); + EXPECT_EQ(value, "Success"); + done = true; + latch.Signal(); + })); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Pump messages for the Windows platform task runner. + ::MSG msg; + while (!done) { + if (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + } + }); + + latch.Wait(); +} + } // namespace testing } // namespace flutter From 4ac21cb7c6e08c833cea1ea9dd812f95e657be41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:39:10 -0700 Subject: [PATCH 13/49] Add completion callback to `Shell::AddView` (#51659) In the future, `FlutterEngineAddView` will be added to the embedder API to allow embedders to add views. `FlutterEngineAddView` will accept a callback that notifies the embedder once the view has been added. This embedder API will be powered by `Shell::AddView`. This change adds a completion callback to `Shell::AddView` to prepare for the embedder API. Design doc: https://flutter.dev/go/multi-view-embedder-apis Part of https://github.com/flutter/flutter/issues/144806 Part of https://github.com/flutter/flutter/issues/142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- lib/ui/window/platform_configuration.cc | 10 +- lib/ui/window/platform_configuration.h | 7 +- runtime/runtime_controller.cc | 70 +++++-- runtime/runtime_controller.h | 42 +++- shell/common/engine.cc | 6 +- shell/common/engine.h | 6 +- shell/common/engine_animator_unittests.cc | 30 ++- shell/common/shell.cc | 15 +- shell/common/shell.h | 7 +- shell/common/shell_unittests.cc | 237 +++++++++++++++++++++- 10 files changed, 386 insertions(+), 44 deletions(-) diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 574b9e27f33ca..e6a934a63c69b 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -83,15 +83,18 @@ void PlatformConfiguration::DidCreateIsolate() { Dart_GetField(library, tonic::ToDart("_reportTimings"))); } -void PlatformConfiguration::AddView(int64_t view_id, +bool PlatformConfiguration::AddView(int64_t view_id, const ViewportMetrics& view_metrics) { auto [view_iterator, insertion_happened] = metrics_.emplace(view_id, view_metrics); - FML_DCHECK(insertion_happened); + if (!insertion_happened) { + FML_LOG(ERROR) << "View #" << view_id << " already exists."; + return false; + } std::shared_ptr dart_state = add_view_.dart_state().lock(); if (!dart_state) { - return; + return false; } tonic::DartState::Scope scope(dart_state); tonic::CheckAndHandleError(tonic::DartInvoke( @@ -119,6 +122,7 @@ void PlatformConfiguration::AddView(int64_t view_id, tonic::ToDart(view_metrics.physical_display_features_state), tonic::ToDart(view_metrics.display_id), })); + return true; } bool PlatformConfiguration::RemoveView(int64_t view_id) { diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 6a583765d962f..b668b85cfd603 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -262,8 +262,7 @@ class PlatformConfigurationClient { /// @brief A class for holding and distributing platform-level information /// to and from the Dart code in Flutter's framework. /// -/// It handles communication between the engine and the framework, -/// and owns the main window. +/// It handles communication between the engine and the framework. /// /// It communicates with the RuntimeController through the use of a /// PlatformConfigurationClient interface, which the @@ -315,7 +314,9 @@ class PlatformConfiguration final { /// @param[in] view_id The ID of the new view. /// @param[in] viewport_metrics The initial viewport metrics for the view. /// - void AddView(int64_t view_id, const ViewportMetrics& view_metrics); + /// @return Whether the view was added. + /// + bool AddView(int64_t view_id, const ViewportMetrics& view_metrics); //---------------------------------------------------------------------------- /// @brief Notify the framework that a view is no longer available. diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index b967b9cde9912..b336b3dde6c83 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -121,12 +121,30 @@ bool RuntimeController::FlushRuntimeStateToIsolate() { FML_DCHECK(!has_flushed_runtime_state_) << "FlushRuntimeStateToIsolate is called more than once somehow."; has_flushed_runtime_state_ = true; + + auto platform_configuration = GetPlatformConfigurationIfAvailable(); + if (!platform_configuration) { + return false; + } + for (auto const& [view_id, viewport_metrics] : platform_data_.viewport_metrics_for_views) { - if (!AddView(view_id, viewport_metrics)) { - return false; + bool added = platform_configuration->AddView(view_id, viewport_metrics); + + // Callbacks will have been already invoked if the engine was restarted. + if (pending_add_view_callbacks_.find(view_id) != + pending_add_view_callbacks_.end()) { + pending_add_view_callbacks_[view_id](added); + pending_add_view_callbacks_.erase(view_id); + } + + if (!added) { + FML_LOG(ERROR) << "Failed to flush view #" << view_id + << ". The Dart isolate may be in an inconsistent state."; } } + + FML_DCHECK(pending_add_view_callbacks_.empty()); return SetLocales(platform_data_.locale_data) && SetSemanticsEnabled(platform_data_.semantics_enabled) && SetAccessibilityFeatures( @@ -136,25 +154,53 @@ bool RuntimeController::FlushRuntimeStateToIsolate() { SetDisplays(platform_data_.displays); } -bool RuntimeController::AddView(int64_t view_id, - const ViewportMetrics& view_metrics) { - platform_data_.viewport_metrics_for_views[view_id] = view_metrics; - if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { - platform_configuration->AddView(view_id, view_metrics); +void RuntimeController::AddView(int64_t view_id, + const ViewportMetrics& view_metrics, + AddViewCallback callback) { + // If the Dart isolate is not running, |FlushRuntimeStateToIsolate| will + // add the view and invoke the callback when the isolate is started. + auto* platform_configuration = GetPlatformConfigurationIfAvailable(); + if (!platform_configuration) { + FML_DCHECK(has_flushed_runtime_state_ == false); + + if (pending_add_view_callbacks_.find(view_id) != + pending_add_view_callbacks_.end()) { + FML_LOG(ERROR) << "View #" << view_id << " is already pending creation."; + callback(false); + return; + } - return true; + platform_data_.viewport_metrics_for_views[view_id] = view_metrics; + pending_add_view_callbacks_[view_id] = std::move(callback); + return; } - return false; + FML_DCHECK(has_flushed_runtime_state_ || pending_add_view_callbacks_.empty()); + + platform_data_.viewport_metrics_for_views[view_id] = view_metrics; + bool added = platform_configuration->AddView(view_id, view_metrics); + callback(added); } bool RuntimeController::RemoveView(int64_t view_id) { platform_data_.viewport_metrics_for_views.erase(view_id); - if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { - return platform_configuration->RemoveView(view_id); + + // If the Dart isolate has not been launched yet, the pending + // add view operation's callback is stored by the runtime controller. + // Notify this callback of the cancellation. + auto* platform_configuration = GetPlatformConfigurationIfAvailable(); + if (!platform_configuration) { + FML_DCHECK(has_flushed_runtime_state_ == false); + if (pending_add_view_callbacks_.find(view_id) != + pending_add_view_callbacks_.end()) { + pending_add_view_callbacks_[view_id](false); + pending_add_view_callbacks_.erase(view_id); + } + + return false; } - return false; + return platform_configuration->RemoveView(view_id); } bool RuntimeController::SetViewportMetrics(int64_t view_id, diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index cb1618f9d3326..8bb01efecabc5 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -50,6 +50,16 @@ class Window; /// class RuntimeController : public PlatformConfigurationClient { public: + /// A callback that's invoked after this `RuntimeController` attempts to + /// add a view to the Dart isolate. + /// + /// If the Dart isolate is not launched yet, this callback will be stored + /// and invoked after the isolate is launched. + /// + /// The `added` parameter is false if the add operation fails or was + /// cancelled while pending using `RemoveView`. + using AddViewCallback = std::function; + //---------------------------------------------------------------------------- /// @brief Creates a new instance of a runtime controller. This is /// usually only done by the engine instance associated with the @@ -174,23 +184,43 @@ class RuntimeController : public PlatformConfigurationClient { /// /// A view must be added before other methods can refer to it, /// including the implicit view. Adding a view that already exists - /// triggers an assertion. + /// is an error. + /// + /// The `callback` is invoked when the add operation is attempted, + /// failed, or is cancelled. + /// + /// If the isolate is not running, the view add will be queued and + /// flushed to the isolate when it starts. Calling `RemoveView` + /// before the isolate is launched cancels the add operation. + /// /// /// @param[in] view_id The ID of the new view. /// @param[in] viewport_metrics The initial viewport metrics for the view. + /// @param[in] callback Callback that will be invoked after the add + /// operation is attempted or cancelled. /// - bool AddView(int64_t view_id, const ViewportMetrics& view_metrics); + void AddView(int64_t view_id, + const ViewportMetrics& view_metrics, + AddViewCallback callback); //---------------------------------------------------------------------------- /// @brief Notify the isolate that a view is no longer available. /// - /// Removing a view that does not exist triggers an assertion. + /// Views that are added before the isolate is started are + /// queued until the isolate is launched. If one of these + /// "pending" views are removed, the view add is cancelled: + /// the `AddViewCallback` will be invoked with an `added` of + /// false and `RemoveView` will return false. /// /// The implicit view (kFlutterImplicitViewId) should never be /// removed. Doing so triggers an assertion. /// /// @param[in] view_id The ID of the view. /// + /// @return If the remove view operation was forwarded to the running + /// isolate. False if the view does not exist. If the Dart isolate + /// is not running, then the pending view creation (if any) is + /// cancelled and the return value is always false. bool RemoveView(int64_t view_id); //---------------------------------------------------------------------------- @@ -660,6 +690,12 @@ class RuntimeController : public PlatformConfigurationClient { std::shared_ptr(new PlatformIsolateManager()); bool has_flushed_runtime_state_ = false; + // Callbacks when `AddView` was called before the Dart isolate is launched. + // + // These views will be added when `FlushRuntimeStateToIsolate` is called. + // This is no longer used once the Dart isolate starts. + std::unordered_map pending_add_view_callbacks_; + // Tracks the views that have been called `Render` during a frame. // // If all views that have been registered by `AddView` have been called diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 7dd03ed19fb78..ac628eb929465 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -297,8 +297,10 @@ tonic::DartErrorHandleType Engine::GetUIIsolateLastError() { return runtime_controller_->GetLastError(); } -void Engine::AddView(int64_t view_id, const ViewportMetrics& view_metrics) { - runtime_controller_->AddView(view_id, view_metrics); +void Engine::AddView(int64_t view_id, + const ViewportMetrics& view_metrics, + std::function callback) { + runtime_controller_->AddView(view_id, view_metrics, std::move(callback)); } bool Engine::RemoveView(int64_t view_id) { diff --git a/shell/common/engine.h b/shell/common/engine.h index 65660f6124c3f..7819ed675cd9f 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -721,8 +721,12 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// /// @param[in] view_id The ID of the new view. /// @param[in] viewport_metrics The initial viewport metrics for the view. + /// @param[in] callback Callback that will be invoked once + /// the engine attempts to add the view. /// - void AddView(int64_t view_id, const ViewportMetrics& view_metrics); + void AddView(int64_t view_id, + const ViewportMetrics& view_metrics, + std::function callback); //---------------------------------------------------------------------------- /// @brief Notify the Flutter application that a view is no diff --git a/shell/common/engine_animator_unittests.cc b/shell/common/engine_animator_unittests.cc index 331bab77e9a16..12bea41da96d3 100644 --- a/shell/common/engine_animator_unittests.cc +++ b/shell/common/engine_animator_unittests.cc @@ -313,8 +313,10 @@ TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders) { engine_context->Run(std::move(configuration)); engine_context->EngineTaskSync([](Engine& engine) { - engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}); - engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}); + engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); + engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); native_latch.Wait(); @@ -368,8 +370,10 @@ TEST_F(EngineAnimatorTest, IgnoresOutOfFrameRenders) { std::move(animator)); engine_context->EngineTaskSync([](Engine& engine) { - engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}); - engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}); + engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); + engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); auto configuration = RunConfiguration::InferFromSettings(settings_); @@ -444,7 +448,8 @@ TEST_F(EngineAnimatorTest, IgnoresDuplicateRenders) { std::move(animator)); engine_context->EngineTaskSync([](Engine& engine) { - engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1, 10, 10, 22, 0}); + engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); auto configuration = RunConfiguration::InferFromSettings(settings_); @@ -504,7 +509,8 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitsImplicitViewBeforeDrawFrameEnds) { std::move(animator)); engine_context->EngineTaskSync([](Engine& engine) { - engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0}); + engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); auto configuration = RunConfiguration::InferFromSettings(settings_); @@ -568,7 +574,8 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitWarmUpImplicitView) { engine.ScheduleFrame(true); // Add the implicit view so that the engine recognizes it and that its // metrics is not empty. - engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0}); + engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); continuation_ready_latch.Wait(); @@ -634,9 +641,12 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitPartialViewsForWarmUp) { // Schedule a frame to make the animator create a continuation. engine.ScheduleFrame(true); // Add multiple views. - engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0}); - engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}); - engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}); + engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); + engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); + engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0}, + [](bool added) { ASSERT_TRUE(added); }); }); continuation_ready_latch.Wait(); diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 0228f2744f72d..8673f4e5c5515 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -754,7 +754,11 @@ bool Shell::Setup(std::unique_ptr platform_view, weak_rasterizer_ = rasterizer_->GetWeakPtr(); weak_platform_view_ = platform_view_->GetWeakPtr(); - engine_->AddView(kFlutterImplicitViewId, ViewportMetrics{}); + // Add the implicit view with empty metrics. + engine_->AddView(kFlutterImplicitViewId, ViewportMetrics{}, [](bool added) { + FML_DCHECK(added) << "Failed to add the implicit view"; + }); + // Setup the time-consuming default font manager right after engine created. if (!settings_.prefetched_default_font_manager) { fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), @@ -2102,7 +2106,9 @@ bool Shell::OnServiceProtocolReloadAssetFonts( return true; } -void Shell::AddView(int64_t view_id, const ViewportMetrics& viewport_metrics) { +void Shell::AddView(int64_t view_id, + const ViewportMetrics& viewport_metrics, + AddViewCallback callback) { TRACE_EVENT0("flutter", "Shell::AddView"); FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); @@ -2112,10 +2118,11 @@ void Shell::AddView(int64_t view_id, const ViewportMetrics& viewport_metrics) { task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr(), // viewport_metrics, // - view_id // + view_id, // + callback = std::move(callback) // ] { if (engine) { - engine->AddView(view_id, viewport_metrics); + engine->AddView(view_id, viewport_metrics, callback); } }); } diff --git a/shell/common/shell.h b/shell/common/shell.h index 3e2da290ed130..a510e141ed6d6 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -133,6 +133,7 @@ class Shell final : public PlatformView::Delegate, const std::shared_ptr& gpu_disabled_switch, impeller::RuntimeStageBackend runtime_stage_type)> EngineCreateCallback; + using AddViewCallback = std::function; using RemoveViewCallback = std::function; //---------------------------------------------------------------------------- @@ -317,8 +318,12 @@ class Shell final : public PlatformView::Delegate, /// /// @param[in] view_id The view ID of the new view. /// @param[in] viewport_metrics The initial viewport metrics for the view. + /// @param[in] callback The callback that's invoked once the engine + /// has attempted to add the view. /// - void AddView(int64_t view_id, const ViewportMetrics& viewport_metrics); + void AddView(int64_t view_id, + const ViewportMetrics& viewport_metrics, + AddViewCallback callback); /// @brief Deallocates resources for a non-implicit view. /// diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index c145f2b8b6da7..0046376bd0ca4 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -4504,8 +4504,10 @@ TEST_F(ShellTest, ShellCanAddViewOrRemoveView) { ASSERT_EQ(viewIds.size(), 1u); ASSERT_EQ(viewIds[0], 0ll); - PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), - [&shell] { shell->AddView(2, ViewportMetrics{}); }); + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell] { + shell->AddView(2, ViewportMetrics{}, + [](bool added) { EXPECT_TRUE(added); }); + }); reportLatch.Wait(); ASSERT_TRUE(hasImplicitView); ASSERT_EQ(viewIds.size(), 2u); @@ -4519,8 +4521,10 @@ TEST_F(ShellTest, ShellCanAddViewOrRemoveView) { ASSERT_EQ(viewIds.size(), 1u); ASSERT_EQ(viewIds[0], 0ll); - PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), - [&shell] { shell->AddView(4, ViewportMetrics{}); }); + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell] { + shell->AddView(4, ViewportMetrics{}, + [](bool added) { EXPECT_TRUE(added); }); + }); reportLatch.Wait(); ASSERT_TRUE(hasImplicitView); ASSERT_EQ(viewIds.size(), 2u); @@ -4530,6 +4534,122 @@ TEST_F(ShellTest, ShellCanAddViewOrRemoveView) { DestroyShell(std::move(shell), task_runners); } +// Test that add view fails if the view ID already exists. +TEST_F(ShellTest, ShellCannotAddDuplicateViewId) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster | + ThreadHost::Type::kIo | ThreadHost::Type::kUi)); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + std::unique_ptr shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + bool has_implicit_view; + std::vector view_ids; + fml::AutoResetWaitableEvent report_latch; + AddNativeCallback("NativeReportViewIdsCallback", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + ParseViewIdsCallback(args, &has_implicit_view, &view_ids); + report_latch.Signal(); + })); + + PlatformViewNotifyCreated(shell.get()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("testReportViewIds"); + RunEngine(shell.get(), std::move(configuration)); + + report_latch.Wait(); + ASSERT_TRUE(has_implicit_view); + ASSERT_EQ(view_ids.size(), 1u); + ASSERT_EQ(view_ids[0], kImplicitViewId); + + // Add view 123. + fml::AutoResetWaitableEvent add_latch; + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), + [&shell, &add_latch] { + shell->AddView(123, ViewportMetrics{}, [&](bool added) { + EXPECT_TRUE(added); + add_latch.Signal(); + }); + }); + + add_latch.Wait(); + + report_latch.Wait(); + ASSERT_EQ(view_ids.size(), 2u); + ASSERT_EQ(view_ids[0], kImplicitViewId); + ASSERT_EQ(view_ids[1], 123); + + // Attempt to add duplicate view ID 123. This should fail. + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), + [&shell, &add_latch] { + shell->AddView(123, ViewportMetrics{}, [&](bool added) { + EXPECT_FALSE(added); + add_latch.Signal(); + }); + }); + + add_latch.Wait(); + + PlatformViewNotifyDestroyed(shell.get()); + DestroyShell(std::move(shell), task_runners); +} + +// Test that remove view fails if the view ID does not exist. +TEST_F(ShellTest, ShellCannotRemoveNonexistentId) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster | + ThreadHost::Type::kIo | ThreadHost::Type::kUi)); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + std::unique_ptr shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + bool has_implicit_view; + std::vector view_ids; + fml::AutoResetWaitableEvent report_latch; + AddNativeCallback("NativeReportViewIdsCallback", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + ParseViewIdsCallback(args, &has_implicit_view, &view_ids); + report_latch.Signal(); + })); + + PlatformViewNotifyCreated(shell.get()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("testReportViewIds"); + RunEngine(shell.get(), std::move(configuration)); + + report_latch.Wait(); + ASSERT_TRUE(has_implicit_view); + ASSERT_EQ(view_ids.size(), 1u); + ASSERT_EQ(view_ids[0], kImplicitViewId); + + // Remove view 123. This should fail as this view doesn't exist. + fml::AutoResetWaitableEvent remove_latch; + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), + [&shell, &remove_latch] { + shell->RemoveView(123, [&](bool removed) { + EXPECT_FALSE(removed); + remove_latch.Signal(); + }); + }); + + remove_latch.Wait(); + + PlatformViewNotifyDestroyed(shell.get()); + DestroyShell(std::move(shell), task_runners); +} + // Parse the arguments of NativeReportViewWidthsCallback and // store them in viewWidths. static void ParseViewWidthsCallback(const Dart_NativeArguments& args, @@ -4570,7 +4690,8 @@ TEST_F(ShellTest, ShellFlushesPlatformStatesByMain) { // The construtor for ViewportMetrics{_, width, _, _, _} (only the 2nd // argument matters in this test). platform_view->SetViewportMetrics(0, ViewportMetrics{1, 10, 1, 0, 0}); - shell->AddView(1, ViewportMetrics{1, 30, 1, 0, 0}); + shell->AddView(1, ViewportMetrics{1, 30, 1, 0, 0}, + [](bool added) { ASSERT_TRUE(added); }); platform_view->SetViewportMetrics(0, ViewportMetrics{1, 20, 1, 0, 0}); }); @@ -4601,6 +4722,112 @@ TEST_F(ShellTest, ShellFlushesPlatformStatesByMain) { DestroyShell(std::move(shell), task_runners); } +// A view can be added and removed before the Dart isolate is launched. +TEST_F(ShellTest, CanRemoveViewBeforeLaunchingIsolate) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster | + ThreadHost::Type::kIo | ThreadHost::Type::kUi)); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + std::unique_ptr shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell] { + auto platform_view = shell->GetPlatformView(); + + // A view can be added and removed all before the isolate launches. + // The pending add view operation is cancelled, the view is never + // added to the Dart isolate. + shell->AddView(123, ViewportMetrics{1, 30, 1, 0, 0}, + [](bool added) { ASSERT_FALSE(added); }); + shell->RemoveView(123, [](bool removed) { ASSERT_FALSE(removed); }); + }); + + bool first_report = true; + std::map view_widths; + fml::AutoResetWaitableEvent report_latch; + AddNativeCallback("NativeReportViewWidthsCallback", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + EXPECT_TRUE(first_report); + first_report = false; + ParseViewWidthsCallback(args, &view_widths); + report_latch.Signal(); + })); + + PlatformViewNotifyCreated(shell.get()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("testReportViewWidths"); + RunEngine(shell.get(), std::move(configuration)); + + report_latch.Wait(); + EXPECT_EQ(view_widths.size(), 1u); + + PlatformViewNotifyDestroyed(shell.get()); + DestroyShell(std::move(shell), task_runners); +} + +// Ensure pending "add views" failures are properly flushed when the Dart +// isolate is launched. +TEST_F(ShellTest, IgnoresBadAddViewsBeforeLaunchingIsolate) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host(ThreadHost::ThreadHostConfig( + "io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster | + ThreadHost::Type::kIo | ThreadHost::Type::kUi)); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + std::unique_ptr shell = CreateShell(settings, task_runners); + ASSERT_TRUE(shell); + + PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell] { + auto platform_view = shell->GetPlatformView(); + + // Add the same view twice. The second time should fail. + shell->AddView(123, ViewportMetrics{1, 100, 1, 0, 0}, + [](bool added) { ASSERT_TRUE(added); }); + + shell->AddView(123, ViewportMetrics{1, 200, 1, 0, 0}, + [](bool added) { ASSERT_FALSE(added); }); + + // Add another view. Previous failures should not affect this. + shell->AddView(456, ViewportMetrics{1, 300, 1, 0, 0}, + [](bool added) { ASSERT_TRUE(added); }); + }); + + bool first_report = true; + std::map view_widths; + fml::AutoResetWaitableEvent report_latch; + AddNativeCallback("NativeReportViewWidthsCallback", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + EXPECT_TRUE(first_report); + first_report = false; + ParseViewWidthsCallback(args, &view_widths); + report_latch.Signal(); + })); + + PlatformViewNotifyCreated(shell.get()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("testReportViewWidths"); + RunEngine(shell.get(), std::move(configuration)); + + report_latch.Wait(); + EXPECT_EQ(view_widths.size(), 3u); + EXPECT_EQ(view_widths[0], 0); + EXPECT_EQ(view_widths[123], 100); + EXPECT_EQ(view_widths[456], 300); + + PlatformViewNotifyDestroyed(shell.get()); + DestroyShell(std::move(shell), task_runners); +} + TEST_F(ShellTest, RuntimeStageBackendDefaultsToSkSLWithoutImpeller) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); From 71b680fc9296f98a7f7c216a28868a990c660828 Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Thu, 28 Mar 2024 18:45:16 -0700 Subject: [PATCH 14/49] Reland https://github.com/flutter/engine/pull/51391 (#51764) --- .../embedding/engine/renderer/FlutterRenderer.java | 8 ++++++++ .../embedding/engine/renderer/FlutterRendererTest.java | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index 3f920cf126b34..df0e5b556a0d3 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -414,6 +414,11 @@ final class ImageReaderSurfaceProducer // Flip when debugging to see verbose logs. private static final boolean VERBOSE_LOGS = false; + // If we cleanup the ImageReaders on memory pressure it breaks VirtualDisplay + // backed platform views. Disable for now as this is only necessary to work + // around a Samsung-specific Android 14 bug. + private static final boolean CLEANUP_ON_MEMORY_PRESSURE = false; + private final long id; private boolean released; @@ -649,6 +654,9 @@ PerImage dequeueImage() { @Override public void onTrimMemory(int level) { + if (!CLEANUP_ON_MEMORY_PRESSURE) { + return; + } cleanup(); createNewReader = true; } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java b/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java index 50f83d5fb8e0a..bc36ed3075f73 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java @@ -648,11 +648,12 @@ public void ImageReaderSurfaceProducerTrimMemoryCallback() { assertEquals(1, texture.numImages()); // Invoke the onTrimMemory callback. + // This should do nothing. texture.onTrimMemory(0); shadowOf(Looper.getMainLooper()).idle(); - assertEquals(0, texture.numImageReaders()); - assertEquals(0, texture.numImages()); + assertEquals(1, texture.numImageReaders()); + assertEquals(1, texture.numImages()); } // A 0x0 ImageReader is a runtime error. From cc8cd242045cd9c739b856b7c823db0a1469daea Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Thu, 28 Mar 2024 19:06:18 -0700 Subject: [PATCH 15/49] [skwasm] Fix `toString` methods on Paint and ImageFilter/ColorFilter (#51766) This fixes https://github.com/flutter/flutter/issues/141639 Most of this was previously unimplemented. It turns out the reason for the hang described in the github issue was that there was a typo in the name of the `getMiterLimit` C function, so if the client actually called that method the Wasm module failed to compile, as it couldn't find an import with the misspelled name. --- .../engine/skwasm/skwasm_impl/filters.dart | 182 +++++++++++++++--- .../src/engine/skwasm/skwasm_impl/paint.dart | 79 +++++++- lib/web_ui/skwasm/paint.cpp | 2 +- lib/web_ui/test/ui/paint_test.dart | 32 ++- 4 files changed, 244 insertions(+), 51 deletions(-) diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart index adc8026ef1d5b..d85668e61f374 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart @@ -2,42 +2,38 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ffi'; import 'dart:typed_data'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart' as ui; -class SkwasmImageFilter extends SkwasmObjectWrapper implements SceneImageFilter { - SkwasmImageFilter._(ImageFilterHandle handle) : super(handle, _registry); +abstract class SkwasmImageFilter extends SkwasmObjectWrapper implements SceneImageFilter { + SkwasmImageFilter(ImageFilterHandle handle) : super(handle, _registry); factory SkwasmImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0, ui.TileMode tileMode = ui.TileMode.clamp, - }) => SkwasmImageFilter._(imageFilterCreateBlur(sigmaX, sigmaY, tileMode.index)); + }) => SkwasmBlurFilter(sigmaX, sigmaY, tileMode); factory SkwasmImageFilter.dilate({ double radiusX = 0.0, double radiusY = 0.0, - }) => SkwasmImageFilter._(imageFilterCreateDilate(radiusX, radiusY)); + }) => SkwasmDilateFilter(radiusX, radiusY); factory SkwasmImageFilter.erode({ double radiusX = 0.0, double radiusY = 0.0, - }) => SkwasmImageFilter._(imageFilterCreateErode(radiusX, radiusY)); + }) => SkwasmErodeFilter(radiusX, radiusY); factory SkwasmImageFilter.matrix( Float64List matrix4, { ui.FilterQuality filterQuality = ui.FilterQuality.low - }) => withStackScope((StackScope scope) => SkwasmImageFilter._(imageFilterCreateMatrix( - scope.convertMatrix4toSkMatrix(matrix4), - filterQuality.index - ))); + }) => SkwasmMatrixFilter(matrix4, filterQuality); factory SkwasmImageFilter.fromColorFilter(SkwasmColorFilter filter) => - SkwasmImageFilter._(imageFilterCreateFromColorFilter(filter.handle)); + SkwasmColorImageFilter(filter); factory SkwasmImageFilter.fromUiFilter(ui.ImageFilter filter) { if (filter is ui.ColorFilter) { @@ -54,11 +50,10 @@ class SkwasmImageFilter extends SkwasmObjectWrapper implements S factory SkwasmImageFilter.compose( ui.ImageFilter outer, ui.ImageFilter inner, - ) { - final SkwasmImageFilter nativeOuter = SkwasmImageFilter.fromUiFilter(outer); - final SkwasmImageFilter nativeInner = SkwasmImageFilter.fromUiFilter(inner); - return SkwasmImageFilter._(imageFilterCompose(nativeOuter.handle, nativeInner.handle)); - } + ) => SkwasmComposedImageFilter( + SkwasmImageFilter.fromUiFilter(outer), + SkwasmImageFilter.fromUiFilter(inner), + ); static final SkwasmFinalizationRegistry _registry = SkwasmFinalizationRegistry(imageFilterDispose); @@ -71,32 +66,161 @@ class SkwasmImageFilter extends SkwasmObjectWrapper implements S }); } -class SkwasmColorFilter extends SkwasmObjectWrapper { - SkwasmColorFilter._(ColorFilterHandle handle) : super(handle, _registry); +class SkwasmBlurFilter extends SkwasmImageFilter { + SkwasmBlurFilter( + this.sigmaX, + this.sigmaY, + this.tileMode, + ) : super(imageFilterCreateBlur(sigmaX, sigmaY, tileMode.index)); + + final double sigmaX; + final double sigmaY; + ui.TileMode tileMode; + + @override + String toString() => 'ImageFilter.blur($sigmaX, $sigmaY, ${tileModeString(tileMode)})'; +} + +class SkwasmDilateFilter extends SkwasmImageFilter { + SkwasmDilateFilter( + this.radiusX, + this.radiusY, + ) : super(imageFilterCreateDilate(radiusX, radiusY)); + + final double radiusX; + final double radiusY; + + @override + String toString() => 'ImageFilter.dilate($radiusX, $radiusY)'; +} + +class SkwasmErodeFilter extends SkwasmImageFilter { + SkwasmErodeFilter( + this.radiusX, + this.radiusY, + ) : super(imageFilterCreateErode(radiusX, radiusY)); + + final double radiusX; + final double radiusY; + + @override + String toString() => 'ImageFilter.erode($radiusX, $radiusY)'; +} + +class SkwasmMatrixFilter extends SkwasmImageFilter { + SkwasmMatrixFilter( + this.matrix4, + this.filterQuality, + ) : super(withStackScope((StackScope scope) => imageFilterCreateMatrix( + scope.convertMatrix4toSkMatrix(matrix4), + filterQuality.index, + ))); + + final Float64List matrix4; + final ui.FilterQuality filterQuality; + + @override + String toString() => 'ImageFilter.matrix($matrix4, $filterQuality)'; +} + +class SkwasmColorImageFilter extends SkwasmImageFilter { + SkwasmColorImageFilter( + this.filter, + ) : super(imageFilterCreateFromColorFilter(filter.handle)); + + final SkwasmColorFilter filter; + + @override + String toString() => filter.toString(); +} + +class SkwasmComposedImageFilter extends SkwasmImageFilter { + SkwasmComposedImageFilter( + this.outer, + this.inner, + ) : super(imageFilterCompose(outer.handle, inner.handle)); + + final SkwasmImageFilter outer; + final SkwasmImageFilter inner; + + @override + String toString() => 'ImageFilter.compose($outer, $inner)'; +} + +abstract class SkwasmColorFilter extends SkwasmObjectWrapper { + SkwasmColorFilter(ColorFilterHandle handle) : super(handle, _registry); factory SkwasmColorFilter.fromEngineColorFilter(EngineColorFilter colorFilter) => switch (colorFilter.type) { - ColorFilterType.mode => SkwasmColorFilter._(colorFilterCreateMode( - colorFilter.color!.value, - colorFilter.blendMode!.index, - )), - ColorFilterType.linearToSrgbGamma => SkwasmColorFilter._(colorFilterCreateLinearToSRGBGamma()), - ColorFilterType.srgbToLinearGamma => SkwasmColorFilter._(colorFilterCreateSRGBToLinearGamma()), - ColorFilterType.matrix => withStackScope((StackScope scope) { - final Pointer nativeMatrix = scope.convertDoublesToNative(colorFilter.matrix!); - return SkwasmColorFilter._(colorFilterCreateMatrix(nativeMatrix)); - }), + ColorFilterType.mode => SkwasmModeColorFilter(colorFilter.color!, colorFilter.blendMode!), + ColorFilterType.linearToSrgbGamma => SkwasmLinearToSrgbGammaColorFilter(), + ColorFilterType.srgbToLinearGamma => SkwasmSrgbToLinearGammaColorFilter(), + ColorFilterType.matrix => SkwasmMatrixColorFilter(colorFilter.matrix!), }; factory SkwasmColorFilter.composed( SkwasmColorFilter outer, SkwasmColorFilter inner, - ) => SkwasmColorFilter._(colorFilterCompose(outer.handle, inner.handle)); + ) => SkwasmComposedColorFilter(outer, inner); static final SkwasmFinalizationRegistry _registry = SkwasmFinalizationRegistry(colorFilterDispose); } +class SkwasmModeColorFilter extends SkwasmColorFilter { + SkwasmModeColorFilter( + this.color, + this.blendMode, + ) : super(colorFilterCreateMode( + color.value, + blendMode.index, + )); + + final ui.Color color; + final ui.BlendMode blendMode; + + @override + String toString() => 'ColorFilter.mode($color, $blendMode)'; +} + +class SkwasmLinearToSrgbGammaColorFilter extends SkwasmColorFilter { + SkwasmLinearToSrgbGammaColorFilter() : super(colorFilterCreateLinearToSRGBGamma()); + + @override + String toString() => 'ColorFilter.linearToSrgbGamma()'; +} + +class SkwasmSrgbToLinearGammaColorFilter extends SkwasmColorFilter { + SkwasmSrgbToLinearGammaColorFilter() : super(colorFilterCreateSRGBToLinearGamma()); + + @override + String toString() => 'ColorFilter.srgbToLinearGamma()'; +} + +class SkwasmMatrixColorFilter extends SkwasmColorFilter { + SkwasmMatrixColorFilter(this.matrix) : super(withStackScope((StackScope scope) => + colorFilterCreateMatrix(scope.convertDoublesToNative(matrix)) + )); + + final List matrix; + + @override + String toString() => 'ColorFilter.matrix($matrix)'; +} + +class SkwasmComposedColorFilter extends SkwasmColorFilter { + SkwasmComposedColorFilter( + this.outer, + this.inner, + ) : super(colorFilterCompose(outer.handle, inner.handle)); + + final SkwasmColorFilter outer; + final SkwasmColorFilter inner; + + @override + String toString() => 'ColorFilter.compose($outer, $inner)'; +} + class SkwasmMaskFilter extends SkwasmObjectWrapper { SkwasmMaskFilter._(MaskFilterHandle handle) : super(handle, _registry); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart index 26e91164134df..507bf94c63ca6 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart @@ -11,6 +11,15 @@ import 'package:ui/ui.dart' as ui; class SkwasmPaint extends SkwasmObjectWrapper implements ui.Paint { SkwasmPaint() : super(paintCreate(), _registry); + // Must be kept in sync with the default in paint.cc. + static const double _kStrokeMiterLimitDefault = 4.0; + + // Must be kept in sync with the default in paint.cc. + static const int _kColorDefault = 0xFF000000; + + // Must be kept in sync with the default in paint.cc. + static final int _kBlendModeDefault = ui.BlendMode.srcOver.index; + static final SkwasmFinalizationRegistry _registry = SkwasmFinalizationRegistry(paintDispose); @@ -173,7 +182,73 @@ class SkwasmPaint extends SkwasmObjectWrapper implements ui.Paint { _setEffectiveColorFilter(); } - // TODO(yjbanov): https://github.com/flutter/flutter/issues/141639 @override - String toString() => 'Paint()'; + String toString() { + String resultString = 'Paint()'; + + assert(() { + final StringBuffer result = StringBuffer(); + String semicolon = ''; + result.write('Paint('); + if (style == ui.PaintingStyle.stroke) { + result.write('$style'); + if (strokeWidth != 0.0) { + result.write(' ${strokeWidth.toStringAsFixed(1)}'); + } else { + result.write(' hairline'); + } + if (strokeCap != ui.StrokeCap.butt) { + result.write(' $strokeCap'); + } + if (strokeJoin == ui.StrokeJoin.miter) { + if (strokeMiterLimit != _kStrokeMiterLimitDefault) { + result.write(' $strokeJoin up to ${strokeMiterLimit.toStringAsFixed(1)}'); + } + } else { + result.write(' $strokeJoin'); + } + semicolon = '; '; + } + if (!isAntiAlias) { + result.write('${semicolon}antialias off'); + semicolon = '; '; + } + if (color != const ui.Color(_kColorDefault)) { + result.write('$semicolon$color'); + semicolon = '; '; + } + if (blendMode.index != _kBlendModeDefault) { + result.write('$semicolon$blendMode'); + semicolon = '; '; + } + if (colorFilter != null) { + result.write('${semicolon}colorFilter: $colorFilter'); + semicolon = '; '; + } + if (maskFilter != null) { + result.write('${semicolon}maskFilter: $maskFilter'); + semicolon = '; '; + } + if (filterQuality != ui.FilterQuality.none) { + result.write('${semicolon}filterQuality: $filterQuality'); + semicolon = '; '; + } + if (shader != null) { + result.write('${semicolon}shader: $shader'); + semicolon = '; '; + } + if (imageFilter != null) { + result.write('${semicolon}imageFilter: $imageFilter'); + semicolon = '; '; + } + if (invertColors) { + result.write('${semicolon}invert: $invertColors'); + } + result.write(')'); + resultString = result.toString(); + return true; + }()); + + return resultString; + } } diff --git a/lib/web_ui/skwasm/paint.cpp b/lib/web_ui/skwasm/paint.cpp index d75264dad42a8..8bba9a5f8a819 100644 --- a/lib/web_ui/skwasm/paint.cpp +++ b/lib/web_ui/skwasm/paint.cpp @@ -82,7 +82,7 @@ SKWASM_EXPORT void paint_setMiterLimit(SkPaint* paint, SkScalar miterLimit) { paint->setStrokeMiter(miterLimit); } -SKWASM_EXPORT SkScalar paint_getMiterLImit(SkPaint* paint) { +SKWASM_EXPORT SkScalar paint_getMiterLimit(SkPaint* paint) { return paint->getStrokeMiter(); } diff --git a/lib/web_ui/test/ui/paint_test.dart b/lib/web_ui/test/ui/paint_test.dart index 4518d08c4d3ec..2c34c77c020c6 100644 --- a/lib/web_ui/test/ui/paint_test.dart +++ b/lib/web_ui/test/ui/paint_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; import '../common/test_initialization.dart'; -import 'utils.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -49,23 +48,18 @@ Future testMain() async { tileMode: ui.TileMode.mirror, ); - if (!isSkwasm) { - expect( - paint.toString(), - 'Paint(' - 'Color(0xaabbccdd); ' - 'BlendMode.darken; ' - 'colorFilter: ColorFilter.linearToSrgbGamma(); ' - 'maskFilter: MaskFilter.blur(BlurStyle.normal, 1.7); ' - 'filterQuality: FilterQuality.high; ' - 'shader: Gradient(); ' - 'imageFilter: ImageFilter.blur(1.9, 2.1, mirror); ' - 'invert: true' - ')', - ); - } else { - // TODO(yjbanov): https://github.com/flutter/flutter/issues/141639 - expect(paint.toString(), 'Paint()'); - } + expect( + paint.toString(), + 'Paint(' + 'Color(0xaabbccdd); ' + 'BlendMode.darken; ' + 'colorFilter: ColorFilter.linearToSrgbGamma(); ' + 'maskFilter: MaskFilter.blur(BlurStyle.normal, 1.7); ' + 'filterQuality: FilterQuality.high; ' + 'shader: Gradient(); ' + 'imageFilter: ImageFilter.blur(1.9, 2.1, mirror); ' + 'invert: true' + ')', + ); }); } From 5f4765fdc948a8192b9028555e6f78aa89bab428 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 28 Mar 2024 23:01:21 -0400 Subject: [PATCH 16/49] Roll Fuchsia Linux SDK from uzI3wnbEGlZ_dtO0Z... to 3vgfbp1vjXkdMZ09m... (#51767) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter-engine Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 221d9f319c385..87f6972c6ef80 100644 --- a/DEPS +++ b/DEPS @@ -1015,7 +1015,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'uzI3wnbEGlZ_dtO0Zp5QFLl5WbvXoUiKu_gjI3PhSykC' + 'version': '3vgfbp1vjXkdMZ09mxspfRoiZfpVNzbnbC3cIjmtgrIC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 3d6812f74af6d..0d60d82ecb06d 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: ed807d849045c39a1539be23d04d0e93 +Signature: 12c107654d7b2e153c88680199c652bb ==================================================================================================== LIBRARY: fuchsia_sdk From 0a4876a97b2fdc2ab414f7fa40f54b6a28c0708c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 02:28:19 -0400 Subject: [PATCH 17/49] Roll Skia from 6042ad386bcf to b2a01ae03cdf (4 revisions) (#51772) https://skia.googlesource.com/skia.git/+log/6042ad386bcf..b2a01ae03cdf 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll Skia Infra from d9a2f3150285 to 33ace26e29f4 (9 revisions) 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll Dawn from 8220ee868483 to 2126889e45aa (11 revisions) 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll SwiftShader from f0178b3c40e7 to ff61926fcedb (2 revisions) 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 61c7aa9a8478 to f91c2fe47c47 (8 revisions) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 87f6972c6ef80..ac5ba5fa56c9f 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '6042ad386bcf6461660d1af7549ff6a3191ea9ff', + 'skia_revision': 'b2a01ae03cdf8f7ac889cd243cd19167d3dbc8f3', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 810c75fb10779..511469fe20d3e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1ca55f2dc76427828e21f5608503d861 +Signature: 3d3d7c034006d9b565c1e0b73cce9307 ==================================================================================================== LIBRARY: etc1 From 6fee660deda74860986cdd94a7a0269e563f9e14 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 03:47:36 -0400 Subject: [PATCH 18/49] Roll Skia from b2a01ae03cdf to 94c0af1297ae (1 revision) (#51773) https://skia.googlesource.com/skia.git/+log/b2a01ae03cdf..94c0af1297ae 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll ANGLE from 21b6899a9c31 to 2b66694d37de (9 revisions) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ac5ba5fa56c9f..0ef744a5a12c0 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'b2a01ae03cdf8f7ac889cd243cd19167d3dbc8f3', + 'skia_revision': '94c0af1297aece58fbf5e5392fc220570fb5fe73', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From b16c0f136cdd76a97854b7ba3550d199fbd694ff Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 10:48:14 -0400 Subject: [PATCH 19/49] Roll Skia from 94c0af1297ae to a12e40efacea (3 revisions) (#51776) https://skia.googlesource.com/skia.git/+log/94c0af1297ae..a12e40efacea 2024-03-29 double1kai@gmail.com fix indentation in SkBlitMask_opts.h 2024-03-29 kjlubick@google.com Remove deprecated hasMipMaps from GrBackendSurface 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll SK Tool from 33ace26e29f4 to dc19502e745f If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0ef744a5a12c0..baff977dd07eb 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '94c0af1297aece58fbf5e5392fc220570fb5fe73', + 'skia_revision': 'a12e40efacea22602d73e44ffb0d283ea156e11a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 511469fe20d3e..5cdd9ee6013a2 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 3d3d7c034006d9b565c1e0b73cce9307 +Signature: 44e8cbcaed3b62ad7ea9dd0ddffa40ec ==================================================================================================== LIBRARY: etc1 From 7176173ea303e28013b575821627e72022842ee8 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 29 Mar 2024 09:11:42 -0700 Subject: [PATCH 20/49] [Impeller] generate mip level N from N-1 in Vulkan backend. (#51749) Uses the mipmap implementation from https://vulkan-tutorial.com/Generating_Mipmaps . Today we generate all mip levels from mip level 0, which results in lost data. Instead we need to use the previous mip level --- .../backend/vulkan/blit_command_vk.cc | 176 ++++++++++-------- 1 file changed, 97 insertions(+), 79 deletions(-) diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index c3c2ebcf88bf1..b5c3d6a147eda 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -6,11 +6,46 @@ #include +#include "impeller/renderer/backend/vulkan/barrier_vk.h" #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "vulkan/vulkan_core.h" +#include "vulkan/vulkan_enums.hpp" +#include "vulkan/vulkan_structs.hpp" namespace impeller { +static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, + const vk::Image& image, + vk::AccessFlags src_access_mask, + vk::AccessFlags dst_access_mask, + vk::ImageLayout old_layout, + vk::ImageLayout new_layout, + vk::PipelineStageFlags src_stage, + vk::PipelineStageFlags dst_stage, + uint32_t base_mip_level, + uint32_t mip_level_count = 1u) { + if (old_layout == new_layout) { + return; + } + + vk::ImageMemoryBarrier barrier; + barrier.srcAccessMask = src_access_mask; + barrier.dstAccessMask = dst_access_mask; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + barrier.subresourceRange.baseMipLevel = base_mip_level; + barrier.subresourceRange.levelCount = mip_level_count; + barrier.subresourceRange.baseArrayLayer = 0u; + barrier.subresourceRange.layerCount = 1u; + + cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier); +} + BlitEncodeVK::~BlitEncodeVK() = default; //------------------------------------------------------------------------------ @@ -240,37 +275,6 @@ std::string BlitGenerateMipmapCommandVK::GetLabel() const { return label; } -static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, - const vk::Image& image, - vk::AccessFlags src_access_mask, - vk::AccessFlags dst_access_mask, - vk::ImageLayout old_layout, - vk::ImageLayout new_layout, - vk::PipelineStageFlags src_stage, - vk::PipelineStageFlags dst_stage, - uint32_t base_mip_level, - uint32_t mip_level_count = 1u) { - if (old_layout == new_layout) { - return; - } - - vk::ImageMemoryBarrier barrier; - barrier.srcAccessMask = src_access_mask; - barrier.dstAccessMask = dst_access_mask; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - barrier.subresourceRange.baseMipLevel = base_mip_level; - barrier.subresourceRange.levelCount = mip_level_count; - barrier.subresourceRange.baseArrayLayer = 0u; - barrier.subresourceRange.layerCount = 1u; - - cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier); -} - bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { auto& src = TextureVK::Cast(*texture); @@ -288,41 +292,56 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { return false; } - // Transition the base mip level to transfer-src layout so we can read from - // it and transition the rest to dst-optimal since they are going to be - // written to. + // Initialize all mip levels to be in TransferDst mode. Later, in a loop, + // after writing to that mip level, we'll first switch its layout to + // TransferSrc to prepare the mip level after it, use the image as the source + // of the blit, before finally switching it to ShaderReadOnly so its available + // for sampling in a shader. InsertImageMemoryBarrier( cmd, // command buffer image, // image vk::AccessFlagBits::eTransferWrite, // src access mask vk::AccessFlagBits::eTransferRead, // dst access mask src.GetLayout(), // old layout - vk::ImageLayout::eTransferSrcOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eTransfer, // dst stage - 0u // mip level - ); - InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - {}, // src access mask - vk::AccessFlagBits::eTransferWrite, // dst access mask - vk::ImageLayout::eUndefined, // old layout vk::ImageLayout::eTransferDstOptimal, // new layout vk::PipelineStageFlagBits::eTransfer, // src stage vk::PipelineStageFlagBits::eTransfer, // dst stage - 1u, // mip level - mip_count - 1 // mip level count + 0u, // mip level + mip_count // mip level count ); - // Blit from the base mip level to all other levels. + vk::ImageMemoryBarrier barrier; + barrier.image = image; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + + // Blit from the mip level N - 1 to mip level N. + size_t width = size.width; + size_t height = size.height; for (size_t mip_level = 1u; mip_level < mip_count; mip_level++) { - vk::ImageBlit blit; + barrier.subresourceRange.baseMipLevel = mip_level - 1; + barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; + barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; + + // We just finished writing to the previous (N-1) mip level or it was the + // base mip level. These were initialized to TransferDst earler. We are now + // going to read from it to write to the current level (N) . So it must be + // converted to TransferSrc. + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, + {barrier}); + vk::ImageBlit blit; blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; blit.srcSubresource.baseArrayLayer = 0u; blit.srcSubresource.layerCount = 1u; - blit.srcSubresource.mipLevel = 0u; + blit.srcSubresource.mipLevel = mip_level - 1; blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; blit.dstSubresource.baseArrayLayer = 0u; @@ -330,13 +349,16 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { blit.dstSubresource.mipLevel = mip_level; // offsets[0] is origin. - blit.srcOffsets[1].x = size.width; - blit.srcOffsets[1].y = size.height; + blit.srcOffsets[1].x = std::max(width, 1u); + blit.srcOffsets[1].y = std::max(height, 1u); blit.srcOffsets[1].z = 1u; + width = width / 2; + height = height / 2; + // offsets[0] is origin. - blit.dstOffsets[1].x = std::max(size.width >> mip_level, 1u); - blit.dstOffsets[1].y = std::max(size.height >> mip_level, 1u); + blit.dstOffsets[1].x = std::max(width, 1u); + blit.dstOffsets[1].y = std::max(height, 1u); blit.dstOffsets[1].z = 1u; cmd.blitImage(image, // src image @@ -347,33 +369,29 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { &blit, // regions vk::Filter::eLinear // filter ); + + barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; + barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; + barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + + // Now that the blit is done, the image at the previous level (N-1) + // is done reading from (TransferSrc)/ Now we must prepare it to be read + // from a shader (ShaderReadOnly). + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, + {barrier}); } - // Transition all mip levels to shader read. The base mip level has a - // different "old" layout than the rest now. - InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - vk::AccessFlagBits::eTransferWrite, // src access mask - vk::AccessFlagBits::eShaderRead, // dst access mask - vk::ImageLayout::eTransferSrcOptimal, // old layout - vk::ImageLayout::eShaderReadOnlyOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eFragmentShader, // dst stage - 0u // mip level - ); - InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - vk::AccessFlagBits::eTransferWrite, // src access mask - vk::AccessFlagBits::eShaderRead, // dst access mask - vk::ImageLayout::eTransferDstOptimal, // old layout - vk::ImageLayout::eShaderReadOnlyOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eFragmentShader, // dst stage - 1u, // mip level - mip_count - 1 // mip level count - ); + barrier.subresourceRange.baseMipLevel = mip_count - 1; + barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; + barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, + {barrier}); // We modified the layouts of this image from underneath it. Tell it its new // state so it doesn't try to perform redundant transitions under the hood. From 79f1530c3dd8b9ca8f73c7e199e1e761481b6bba Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Fri, 29 Mar 2024 12:50:01 -0400 Subject: [PATCH 21/49] [web] Use viewId for text editing (#51099) Handle `viewId` for text fields. Part of https://github.com/flutter/flutter/issues/137344 --- .../view_focus_binding.dart | 7 +- .../src/engine/text_editing/text_editing.dart | 62 +++- .../view_embedder/flutter_view_manager.dart | 20 +- lib/web_ui/test/engine/composition_test.dart | 14 +- .../engine/semantics/text_field_test.dart | 3 +- lib/web_ui/test/engine/text_editing_test.dart | 308 ++++++++++++++++-- .../flutter_view_manager_test.dart | 71 +++- 7 files changed, 419 insertions(+), 66 deletions(-) diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart b/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart index 1dc10b9fef846..4ec158546337b 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart @@ -95,11 +95,8 @@ final class ViewFocusBinding { } int? _viewId(DomElement? element) { - final DomElement? rootElement = element?.closest(DomManager.flutterViewTagName); - if (rootElement == null) { - return null; - } - return _viewManager.viewIdForRootElement(rootElement); + final FlutterViewManager viewManager = EnginePlatformDispatcher.instance.viewManager; + return viewManager.findViewForElement(element)?.viewId; } void _handleViewCreated(int viewId) { diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index 672a5ad3be61d..ac3c7b187fedf 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -18,6 +18,8 @@ import '../semantics.dart'; import '../services.dart'; import '../text/paragraph.dart'; import '../util.dart'; +import '../view_embedder/flutter_view_manager.dart'; +import '../window.dart'; import 'autofill_hint.dart'; import 'composition_aware_mixin.dart'; import 'input_action.dart'; @@ -48,12 +50,6 @@ const String transparentTextEditingClass = 'transparentTextEditing'; void _emptyCallback(dynamic _) {} -/// The default [HostNode] that hosts all DOM required for text editing when a11y is not enabled. -@visibleForTesting -// TODO(mdebbar): There could be multiple views with multiple text editing hosts. -// https://github.com/flutter/flutter/issues/137344 -DomElement get defaultTextEditingRoot => EnginePlatformDispatcher.instance.implicitView!.dom.textEditingHost; - /// These style attributes are constant throughout the life time of an input /// element. /// @@ -147,6 +143,37 @@ void _styleAutofillElements( elementStyle.setProperty('caret-color', 'transparent'); } +void _ensureEditingElementInView(DomElement element, int viewId) { + final bool isAlreadyAppended = element.isConnected ?? false; + if (!isAlreadyAppended) { + // If the element is not already appended to a view, we don't need to move + // it anywhere. + return; + } + + final FlutterViewManager viewManager = EnginePlatformDispatcher.instance.viewManager; + final EngineFlutterView? currentView = viewManager.findViewForElement(element); + if (currentView == null) { + // For some reason, the input element was in the DOM, but it wasn't part of + // any Flutter view. Should we throw? + return; + } + + if (currentView.viewId != viewId) { + _insertEditingElementInView(element, viewId); + } +} + +void _insertEditingElementInView(DomElement element, int viewId) { + final FlutterViewManager viewManager = EnginePlatformDispatcher.instance.viewManager; + final EngineFlutterView? view = viewManager[viewId]; + assert( + view != null, + 'Could not find View with id $viewId. This should never happen, please file a bug!', + ); + view!.dom.textEditingHost.append(element); +} + /// Form that contains all the fields in the same AutofillGroup. /// /// An [EngineAutofillForm] will only be constructed when autofill is enabled @@ -154,6 +181,7 @@ void _styleAutofillElements( /// static method. class EngineAutofillForm { EngineAutofillForm({ + required this.viewId, required this.formElement, this.elements, this.items, @@ -177,6 +205,9 @@ class EngineAutofillForm { /// See [formsOnTheDom]. final String formIdentifier; + /// The ID of the view that this form is rendered into. + final int viewId; + /// Creates an [EngineAutofillFrom] from the JSON representation of a Flutter /// framework `TextInputConfiguration` object. /// @@ -189,6 +220,7 @@ class EngineAutofillForm { /// /// Returns null if autofill is disabled for the input field. static EngineAutofillForm? fromFrameworkMessage( + int viewId, Map? focusedElementAutofill, List? fields, ) { @@ -312,6 +344,7 @@ class EngineAutofillForm { insertionReferenceNode ??= submitButton; return EngineAutofillForm( + viewId: viewId, formElement: formElement, elements: elements, items: items, @@ -330,7 +363,7 @@ class EngineAutofillForm { } formElement.insertBefore(mainTextEditingElement, insertionReferenceNode); - defaultTextEditingRoot.append(formElement); + _insertEditingElementInView(formElement, viewId); } void storeForm() { @@ -944,6 +977,7 @@ class EditingState { /// This corresponds to Flutter's [TextInputConfiguration]. class InputConfiguration { InputConfiguration({ + required this.viewId, this.inputType = EngineInputType.text, this.inputAction = 'TextInputAction.done', this.obscureText = false, @@ -958,7 +992,8 @@ class InputConfiguration { InputConfiguration.fromFrameworkMessage( Map flutterInputConfiguration) - : inputType = EngineInputType.fromName( + : viewId = flutterInputConfiguration.tryInt('viewId') ?? kImplicitViewId, + inputType = EngineInputType.fromName( flutterInputConfiguration.readJson('inputType').readString('name'), isDecimal: flutterInputConfiguration.readJson('inputType').tryBool('decimal') ?? false, isMultiline: flutterInputConfiguration.readJson('inputType').tryBool('isMultiline') ?? false, @@ -976,11 +1011,15 @@ class InputConfiguration { flutterInputConfiguration.readJson('autofill')) : null, autofillGroup = EngineAutofillForm.fromFrameworkMessage( + flutterInputConfiguration.tryInt('viewId') ?? kImplicitViewId, flutterInputConfiguration.tryJson('autofill'), flutterInputConfiguration.tryList('fields'), ), enableDeltaModel = flutterInputConfiguration.tryBool('enableDeltaModel') ?? false; + /// The ID of the view that contains the text field. + final int viewId; + /// The type of information being edited in the input control. final EngineInputType inputType; @@ -1257,7 +1296,7 @@ abstract class DefaultTextEditingStrategy with CompositionAwareMixin implements // DOM later, when the first location information arrived. // Otherwise, on Blink based Desktop browsers, the autofill menu appears // on top left of the screen. - defaultTextEditingRoot.append(activeDomElement); + _insertEditingElementInView(activeDomElement, inputConfig.viewId); _appendedToForm = false; } @@ -1293,6 +1332,9 @@ abstract class DefaultTextEditingStrategy with CompositionAwareMixin implements autofill.applyToDomElement(activeDomElement, focusedElement: true); } else { activeDomElement.setAttribute('autocomplete', 'off'); + // When the new input configuration contains a different view ID, we need + // to move the input element to the new view. + _ensureEditingElementInView(activeDomElement, inputConfiguration.viewId); } final String autocorrectValue = config.autocorrect ? 'on' : 'off'; @@ -1757,7 +1799,7 @@ class AndroidTextEditingStrategy extends GloballyPositionedTextEditingStrategy { if (hasAutofillGroup) { placeForm(); } else { - defaultTextEditingRoot.append(activeDomElement); + _insertEditingElementInView(activeDomElement, inputConfig.viewId); } inputConfig.textCapitalization.setAutocapitalizeAttribute( activeDomElement); diff --git a/lib/web_ui/lib/src/engine/view_embedder/flutter_view_manager.dart b/lib/web_ui/lib/src/engine/view_embedder/flutter_view_manager.dart index 684e5ea667c22..2d2bc639e361a 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/flutter_view_manager.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/flutter_view_manager.dart @@ -12,12 +12,15 @@ class FlutterViewManager { // A map of EngineFlutterViews indexed by their viewId. final Map _viewData = {}; + // A map of (optional) JsFlutterViewOptions, indexed by their viewId. final Map _jsViewOptions = {}; + // The controller of the [onViewCreated] stream. final StreamController _onViewCreatedController = StreamController.broadcast(sync: true); + // The controller of the [onViewDisposed] stream. final StreamController _onViewDisposedController = StreamController.broadcast(sync: true); @@ -82,7 +85,7 @@ class FlutterViewManager { /// /// Returns its [JsFlutterViewOptions] (if any). JsFlutterViewOptions? unregisterView(int viewId) { - _viewData.remove(viewId); // .dispose(); + _viewData.remove(viewId); final JsFlutterViewOptions? jsViewOptions = _jsViewOptions.remove(viewId); _onViewDisposedController.add(viewId); return jsViewOptions; @@ -96,14 +99,13 @@ class FlutterViewManager { return _jsViewOptions[viewId]; } - /// Returns the [viewId] if [rootElement] corresponds to any of the [views]. - int? viewIdForRootElement(DomElement rootElement) { - for(final EngineFlutterView view in views) { - if (view.dom.rootElement == rootElement) { - return view.viewId; - } - } - return null; + EngineFlutterView? findViewForElement(DomElement? element) { + const String viewRootSelector = + '${DomManager.flutterViewTagName}[${GlobalHtmlAttributes.flutterViewIdAttributeName}]'; + final DomElement? viewRoot = element?.closest(viewRootSelector); + final String? viewIdAttribute = viewRoot?.getAttribute(GlobalHtmlAttributes.flutterViewIdAttributeName); + final int? viewId = viewIdAttribute == null ? null : int.parse(viewIdAttribute); + return viewId == null ? null : _viewData[viewId]; } void dispose() { diff --git a/lib/web_ui/test/engine/composition_test.dart b/lib/web_ui/test/engine/composition_test.dart index 6e743139bd47d..75551745b3d56 100644 --- a/lib/web_ui/test/engine/composition_test.dart +++ b/lib/web_ui/test/engine/composition_test.dart @@ -6,14 +6,13 @@ import 'dart:async'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/browser_detection.dart'; - -import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/text_editing/composition_aware_mixin.dart'; -import 'package:ui/src/engine/text_editing/text_editing.dart'; +import 'package:ui/src/engine.dart'; import '../common/test_initialization.dart'; +DomElement get defaultTextEditingRoot => + EnginePlatformDispatcher.instance.implicitView!.dom.textEditingHost; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -36,7 +35,10 @@ GloballyPositionedTextEditingStrategy _enableEditingStrategy({ }) { final HybridTextEditing owner = HybridTextEditing(); - owner.configuration = InputConfiguration(enableDeltaModel: deltaModel); + owner.configuration = InputConfiguration( + viewId: kImplicitViewId, + enableDeltaModel: deltaModel, + ); final GloballyPositionedTextEditingStrategy editingStrategy = GloballyPositionedTextEditingStrategy(owner); diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index 60e4cbaa31487..52a41b1ae197d 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -15,9 +15,10 @@ import 'package:ui/ui.dart' as ui; import '../../common/test_initialization.dart'; import 'semantics_tester.dart'; -final InputConfiguration singlelineConfig = InputConfiguration(); +final InputConfiguration singlelineConfig = InputConfiguration(viewId: kImplicitViewId); final InputConfiguration multilineConfig = InputConfiguration( + viewId: kImplicitViewId, inputType: EngineInputType.multiline, inputAction: 'TextInputAction.newline', ); diff --git a/lib/web_ui/test/engine/text_editing_test.dart b/lib/web_ui/test/engine/text_editing_test.dart index a9fa99443eb5b..1d9b026f2414f 100644 --- a/lib/web_ui/test/engine/text_editing_test.dart +++ b/lib/web_ui/test/engine/text_editing_test.dart @@ -8,16 +8,7 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; - -import 'package:ui/src/engine/browser_detection.dart'; -import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/raw_keyboard.dart'; -import 'package:ui/src/engine/services.dart'; -import 'package:ui/src/engine/text_editing/autofill_hint.dart'; -import 'package:ui/src/engine/text_editing/input_type.dart'; -import 'package:ui/src/engine/text_editing/text_editing.dart'; -import 'package:ui/src/engine/util.dart'; -import 'package:ui/src/engine/vector_math.dart'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import '../common/spy.dart'; @@ -28,6 +19,11 @@ const int _kReturnKeyCode = 13; const MethodCodec codec = JSONMethodCodec(); +EnginePlatformDispatcher get dispatcher => EnginePlatformDispatcher.instance; + +DomElement get defaultTextEditingRoot => + dispatcher.implicitView!.dom.textEditingHost; + /// Add unit tests for [FirefoxTextEditingStrategy]. // TODO(mdebbar): https://github.com/flutter/flutter/issues/46891 @@ -36,11 +32,14 @@ EditingState? lastEditingState; TextEditingDeltaState? editingDeltaState; String? lastInputAction; -final InputConfiguration singlelineConfig = InputConfiguration(); +final InputConfiguration singlelineConfig = InputConfiguration( + viewId: kImplicitViewId, +); final Map flutterSinglelineConfig = createFlutterConfig('text'); final InputConfiguration multilineConfig = InputConfiguration( + viewId: kImplicitViewId, inputType: EngineInputType.multiline, inputAction: 'TextInputAction.newline', ); @@ -129,8 +128,38 @@ Future testMain() async { domDocument.body); }); + test('inserts element in the correct view', () { + final DomElement host = createDomElement('div'); + domDocument.body!.append(host); + final EngineFlutterView view = EngineFlutterView(dispatcher, host); + dispatcher.viewManager.registerView(view); + final DomElement textEditingHost = view.dom.textEditingHost; + + expect(domDocument.getElementsByTagName('input'), hasLength(0)); + expect(textEditingHost.getElementsByTagName('input'), hasLength(0)); + + final InputConfiguration config = InputConfiguration(viewId: view.viewId); + editingStrategy!.enable( + config, + onChange: trackEditingState, + onAction: trackInputAction, + ); + final DomElement input = editingStrategy!.domElement!; + + // Input is appended to the right view. + expect(textEditingHost.contains(input), isTrue); + + // Cleanup. + editingStrategy!.disable(); + expect(textEditingHost.querySelectorAll('input'), hasLength(0)); + dispatcher.viewManager.unregisterView(view.viewId); + view.dispose(); + host.remove(); + }); + test('Respects read-only config', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, readOnly: true, ); editingStrategy!.enable( @@ -148,6 +177,7 @@ Future testMain() async { test('Knows how to create password fields', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, obscureText: true, ); editingStrategy!.enable( @@ -165,6 +195,7 @@ Future testMain() async { test('Knows how to create non-default text actions', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, inputAction: 'TextInputAction.send' ); editingStrategy!.enable( @@ -186,6 +217,7 @@ Future testMain() async { test('Knows to turn autocorrect off', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, autocorrect: false, ); editingStrategy!.enable( @@ -202,7 +234,7 @@ Future testMain() async { }); test('Knows to turn autocorrect on', () { - final InputConfiguration config = InputConfiguration(); + final InputConfiguration config = InputConfiguration(viewId: kImplicitViewId); editingStrategy!.enable( config, onChange: trackEditingState, @@ -217,7 +249,7 @@ Future testMain() async { }); test('Knows to turn autofill off', () { - final InputConfiguration config = InputConfiguration(); + final InputConfiguration config = InputConfiguration(viewId: kImplicitViewId); editingStrategy!.enable( config, onChange: trackEditingState, @@ -352,7 +384,7 @@ Future testMain() async { }); test('Triggers input action', () { - final InputConfiguration config = InputConfiguration(); + final InputConfiguration config = InputConfiguration(viewId: kImplicitViewId); editingStrategy!.enable( config, onChange: trackEditingState, @@ -371,10 +403,10 @@ Future testMain() async { }); test('handling keyboard event prevents triggering input action', () { - final ui.PlatformMessageCallback? savedCallback = ui.PlatformDispatcher.instance.onPlatformMessage; + final ui.PlatformMessageCallback? savedCallback = dispatcher.onPlatformMessage; bool markTextEventHandled = false; - ui.PlatformDispatcher.instance.onPlatformMessage = (String channel, ByteData? data, + dispatcher.onPlatformMessage = (String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback) { final ByteData response = const JSONMessageCodec() .encodeMessage({'handled': markTextEventHandled})!; @@ -382,7 +414,7 @@ Future testMain() async { }; RawKeyboard.initialize(); - final InputConfiguration config = InputConfiguration(); + final InputConfiguration config = InputConfiguration(viewId: kImplicitViewId); editingStrategy!.enable( config, onChange: trackEditingState, @@ -412,12 +444,13 @@ Future testMain() async { // Input action received. expect(lastInputAction, 'TextInputAction.done'); - ui.PlatformDispatcher.instance.onPlatformMessage = savedCallback; + dispatcher.onPlatformMessage = savedCallback; RawKeyboard.instance?.dispose(); }); test('Triggers input action in multi-line mode', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, inputType: EngineInputType.multiline, ); editingStrategy!.enable( @@ -443,6 +476,7 @@ Future testMain() async { test('Triggers input action in multiline-none mode', () { final InputConfiguration config = InputConfiguration( + viewId: kImplicitViewId, inputType: EngineInputType.multilineNone, ); editingStrategy!.enable( @@ -468,7 +502,7 @@ Future testMain() async { test('Triggers input action and prevent new line key event for single line field', () { // Regression test for https://github.com/flutter/flutter/issues/113559 - final InputConfiguration config = InputConfiguration(); + final InputConfiguration config = InputConfiguration(viewId: kImplicitViewId); editingStrategy!.enable( config, onChange: trackEditingState, @@ -590,16 +624,24 @@ Future testMain() async { /// Returns the `clientId` used in the platform message. int showKeyboard({ required String inputType, + int? viewId, String? inputAction, bool decimal = false, bool isMultiline = false, + bool autofillEnabled = true, }) { final MethodCall setClient = MethodCall( 'TextInput.setClient', [ ++clientId, - createFlutterConfig(inputType, - inputAction: inputAction, decimal: decimal, isMultiline: isMultiline), + createFlutterConfig( + inputType, + viewId: viewId, + inputAction: inputAction, + decimal: decimal, + isMultiline: isMultiline, + autofillEnabled: autofillEnabled, + ), ], ); sendFrameworkMessage(codec.encodeMethodCall(setClient)); @@ -2481,6 +2523,186 @@ Future testMain() async { expect(event.defaultPrevented, isFalse); }); + test('inserts element in the correct view', () async { + final DomElement host = createDomElement('div'); + domDocument.body!.append(host); + final EngineFlutterView view = EngineFlutterView(dispatcher, host); + dispatcher.viewManager.registerView(view); + + textEditing = HybridTextEditing(); + showKeyboard(inputType: 'text', viewId: view.viewId); + // The Safari strategy doesn't insert the input element into the DOM until + // it has received the geometry information. + final List transform = Matrix4.identity().storage.toList(); + final MethodCall setSizeAndTransform = configureSetSizeAndTransformMethodCall(10, 10, transform); + sendFrameworkMessage(codec.encodeMethodCall(setSizeAndTransform)); + + await waitForDesktopSafariFocus(); + + final DomElement input = textEditing!.strategy.domElement!; + + + // Input is appended to the right view. + expect(view.dom.textEditingHost.contains(input), isTrue); + + // Cleanup. + hideKeyboard(); + dispatcher.viewManager.unregisterView(view.viewId); + view.dispose(); + host.remove(); + }); + + test('moves element to correct view', () { + final DomElement host1 = createDomElement('div'); + domDocument.body!.append(host1); + final EngineFlutterView view1 = EngineFlutterView(dispatcher, host1); + dispatcher.viewManager.registerView(view1); + + final DomElement host2 = createDomElement('div'); + domDocument.body!.append(host2); + final EngineFlutterView view2 = EngineFlutterView(dispatcher, host2); + dispatcher.viewManager.registerView(view2); + + textEditing = HybridTextEditing(); + showKeyboard(inputType: 'text', viewId: view1.viewId, autofillEnabled: false); + + final DomElement input = textEditing!.strategy.domElement!; + + // Input is appended to view1. + expect(view1.dom.textEditingHost.contains(input), isTrue); + + sendFrameworkMessage(codec.encodeMethodCall(MethodCall( + 'TextInput.updateConfig', + createFlutterConfig('text', viewId: view2.viewId, autofillEnabled: false), + ))); + + // The input element is the same (no new element was created), but it has + // moved to view2. + expect(textEditing!.strategy.domElement, input); + expect(view2.dom.textEditingHost.contains(input), isTrue); + + // Cleanup. + hideKeyboard(); + dispatcher.viewManager.unregisterView(view1.viewId); + view1.dispose(); + dispatcher.viewManager.unregisterView(view2.viewId); + view2.dispose(); + host1.remove(); + host2.remove(); + }); + + test('places autofill form in the correct view', () async { + final DomElement host = createDomElement('div'); + domDocument.body!.append(host); + final EngineFlutterView view = EngineFlutterView(dispatcher, host); + dispatcher.viewManager.registerView(view); + + textEditing = HybridTextEditing(); + + // Create a configuration with an AutofillGroup of three text fields. + final Map flutterMultiAutofillElementConfig = + createFlutterConfig( + 'text', + viewId: view.viewId, + autofillHint: 'username', + autofillHintsForFields: ['username', 'email', 'name'], + ); + final MethodCall setClient = MethodCall( + 'TextInput.setClient', + [123, flutterMultiAutofillElementConfig], + ); + sendFrameworkMessage(codec.encodeMethodCall(setClient)); + + const MethodCall show = MethodCall('TextInput.show'); + sendFrameworkMessage(codec.encodeMethodCall(show)); + // The Safari strategy doesn't insert the input element into the DOM until + // it has received the geometry information. + final List transform = Matrix4.identity().storage.toList(); + final MethodCall setSizeAndTransform = configureSetSizeAndTransformMethodCall(10, 10, transform); + sendFrameworkMessage(codec.encodeMethodCall(setSizeAndTransform)); + + await waitForDesktopSafariFocus(); + + final DomElement input = textEditing!.strategy.domElement!; + final DomElement form = textEditing!.configuration!.autofillGroup!.formElement; + + // Input and form are appended to the right view. + expect(view.dom.textEditingHost.contains(input), isTrue); + expect(view.dom.textEditingHost.contains(form), isTrue); + + // Cleanup. + hideKeyboard(); + dispatcher.viewManager.unregisterView(view.viewId); + view.dispose(); + host.remove(); + }); + + test('moves autofill form to the correct view', () async { + final DomElement host1 = createDomElement('div'); + domDocument.body!.append(host1); + final EngineFlutterView view1 = EngineFlutterView(dispatcher, host1); + dispatcher.viewManager.registerView(view1); + + final DomElement host2 = createDomElement('div'); + domDocument.body!.append(host2); + final EngineFlutterView view2 = EngineFlutterView(dispatcher, host2); + dispatcher.viewManager.registerView(view2); + + textEditing = HybridTextEditing(); + + // Create a configuration with an AutofillGroup of three text fields. + final Map autofillConfig1 = createFlutterConfig( + 'text', + viewId: view1.viewId, + autofillHint: 'username', + autofillHintsForFields: ['username', 'email', 'name'], + ); + final MethodCall setClient = MethodCall( + 'TextInput.setClient', + [123, autofillConfig1], + ); + sendFrameworkMessage(codec.encodeMethodCall(setClient)); + + const MethodCall show = MethodCall('TextInput.show'); + sendFrameworkMessage(codec.encodeMethodCall(show)); + + await waitForDesktopSafariFocus(); + + final DomElement input = textEditing!.strategy.domElement!; + final DomElement form = textEditing!.configuration!.autofillGroup!.formElement; + + // Input and form are appended to view1. + expect(view1.dom.textEditingHost.contains(input), isTrue); + expect(view1.dom.textEditingHost.contains(form), isTrue); + + // Move the input and form to view2. + final Map autofillConfig2 = createFlutterConfig( + 'text', + viewId: view2.viewId, + autofillHint: 'username', + autofillHintsForFields: ['username', 'email', 'name'], + ); + sendFrameworkMessage(codec.encodeMethodCall(MethodCall( + 'TextInput.updateConfig', + autofillConfig2, + ))); + + // Input and form are in view2. + expect(view2.dom.textEditingHost.contains(input), isTrue); + expect(view2.dom.textEditingHost.contains(form), isTrue); + + // Cleanup. + hideKeyboard(); + dispatcher.viewManager.unregisterView(view1.viewId); + view1.dispose(); + dispatcher.viewManager.unregisterView(view2.viewId); + view2.dispose(); + host1.remove(); + host2.remove(); + // TODO(mdebbar): Autofill forms don't get updated in the current system. + // https://github.com/flutter/flutter/issues/145101 + }, skip: true); + tearDown(() { clearForms(); }); @@ -2493,7 +2715,10 @@ Future testMain() async { ['field1', 'field2', 'field3']); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('username', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('username', 'field1'), + fields, + )!; // Number of elements if number of fields sent to the constructor minus // one (for the focused text element). @@ -2550,7 +2775,10 @@ Future testMain() async { ['zzyyxx', 'aabbcc', 'jjkkll']); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('username', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('username', 'field1'), + fields, + )!; expect(autofillForm.formIdentifier, 'aabbcc*jjkkll*zzyyxx'); }); @@ -2563,7 +2791,10 @@ Future testMain() async { ['field1', 'fields2', 'field3']); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('username', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('username', 'field1'), + fields, + )!; final DomHTMLInputElement testInputElement = createDomHTMLInputElement(); autofillForm.placeForm(testInputElement); @@ -2590,7 +2821,10 @@ Future testMain() async { ); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('username', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('username', 'field1'), + fields, + )!; // The focused element is the only field. Form should be empty after // the initialization (focus element is appended later). @@ -2615,7 +2849,7 @@ Future testMain() async { ['field1'], ); final EngineAutofillForm? autofillForm = - EngineAutofillForm.fromFrameworkMessage(null, fields); + EngineAutofillForm.fromFrameworkMessage(kImplicitViewId, null, fields); expect(autofillForm, isNull); }); @@ -2632,7 +2866,10 @@ Future testMain() async { ]); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('email', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('email', 'field1'), + fields, + )!; expect(autofillForm.elements, hasLength(2)); @@ -2675,7 +2912,10 @@ Future testMain() async { ]); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('email', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('email', 'field1'), + fields, + )!; final List formChildNodes = autofillForm.formElement.childNodes.toList() as List; @@ -2707,7 +2947,10 @@ Future testMain() async { ]); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('email', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('email', 'field1'), + fields, + )!; final List formChildNodes = autofillForm.formElement.childNodes.toList() as List; @@ -2738,7 +2981,10 @@ Future testMain() async { ]); final EngineAutofillForm autofillForm = EngineAutofillForm.fromFrameworkMessage( - createAutofillInfo('email', 'field1'), fields)!; + kImplicitViewId, + createAutofillInfo('email', 'field1'), + fields, + )!; final DomHTMLInputElement testInputElement = createDomHTMLInputElement(); testInputElement.name = 'email'; @@ -3378,6 +3624,7 @@ void checkTextAreaEditingState( /// simplicity. Map createFlutterConfig( String inputType, { + int? viewId, bool readOnly = false, bool obscureText = false, bool autocorrect = true, @@ -3397,6 +3644,7 @@ Map createFlutterConfig( if (decimal) 'decimal': true, if (isMultiline) 'isMultiline': true, }, + if (viewId != null) 'viewId': viewId, 'readOnly': readOnly, 'obscureText': obscureText, 'autocorrect': autocorrect, diff --git a/lib/web_ui/test/engine/view_embedder/flutter_view_manager_test.dart b/lib/web_ui/test/engine/view_embedder/flutter_view_manager_test.dart index 5dbec513268d0..3ff2cd027e1df 100644 --- a/lib/web_ui/test/engine/view_embedder/flutter_view_manager_test.dart +++ b/lib/web_ui/test/engine/view_embedder/flutter_view_manager_test.dart @@ -102,13 +102,74 @@ Future doTests() async { }); }); - group('viewIdForRootElement', () { - test('works', () { - final EngineFlutterView view = EngineFlutterView(platformDispatcher, createDomElement('div')); - final int viewId = view.viewId; + group('findViewForElement', () { + test('finds view for root and descendant elements', () { + final DomElement host = createDomElement('div'); + final EngineFlutterView view = EngineFlutterView(platformDispatcher, host); + + viewManager.registerView(view); + + final DomElement rootElement = view.dom.rootElement; + final DomElement child1 = createDomElement('div'); + final DomElement child2 = createDomElement('div'); + final DomElement child3 = createDomElement('div'); + rootElement.append(child1); + rootElement.append(child2); + child2.append(child3); + + expect(viewManager.findViewForElement(rootElement), view); + expect(viewManager.findViewForElement(child1), view); + expect(viewManager.findViewForElement(child2), view); + expect(viewManager.findViewForElement(child3), view); + }); + + test('returns null for host element', () { + final DomElement host = createDomElement('div'); + final EngineFlutterView view = EngineFlutterView(platformDispatcher, host); + viewManager.registerView(view); + + expect(viewManager.findViewForElement(host), isNull); + }); + + test("returns null for elements that don't belong to any view", () { + final DomElement host = createDomElement('div'); + final EngineFlutterView view = EngineFlutterView(platformDispatcher, host); + viewManager.registerView(view); + + final DomElement disconnectedElement = createDomElement('div'); + final DomElement childOfBody = createDomElement('div'); + + domDocument.body!.append(childOfBody); + + expect(viewManager.findViewForElement(disconnectedElement), isNull); + expect(viewManager.findViewForElement(childOfBody), isNull); + expect(viewManager.findViewForElement(domDocument.body), isNull); + }); + + test('does not recognize elements from unregistered views', () { + final DomElement host = createDomElement('div'); + final EngineFlutterView view = EngineFlutterView(platformDispatcher, host); viewManager.registerView(view); - expect(viewManager.viewIdForRootElement(view.dom.rootElement), viewId); + final DomElement rootElement = view.dom.rootElement; + final DomElement child1 = createDomElement('div'); + final DomElement child2 = createDomElement('div'); + final DomElement child3 = createDomElement('div'); + rootElement.append(child1); + rootElement.append(child2); + child2.append(child3); + + expect(viewManager.findViewForElement(rootElement), view); + expect(viewManager.findViewForElement(child1), view); + expect(viewManager.findViewForElement(child2), view); + expect(viewManager.findViewForElement(child3), view); + + viewManager.unregisterView(view.viewId); + + expect(viewManager.findViewForElement(rootElement), isNull); + expect(viewManager.findViewForElement(child1), isNull); + expect(viewManager.findViewForElement(child2), isNull); + expect(viewManager.findViewForElement(child3), isNull); }); }); }); From 8630c4baf67e96985284fea461be124f0a191b1e Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 10:36:08 -0700 Subject: [PATCH 22/49] Implement `.engine-release.version` files for engine Skia Gold tests (#51739) Work towards https://github.com/flutter/flutter/issues/144835. Doc (_sorry, internal only_): [go/flutter-engine-goldens-workflow](http://goto.google.com/flutter-engine-goldens-workflow). This implements the majority of the proposed workflow, that is, optionally having a plain-text version at the root of the directory, and using it to apply a unique suffix we can review in release branches. As it stands, this is a NO-OP outside of tests (it will have no impact, and can be ignored). What's missing before using this feature in release branches: - Optimization work with the infra team (not sure if blocking or not): https://github.com/flutter/flutter/issues/145842 - A dry-run of this with the release team to make sure it works as intended @gaaclarke As implemented, I _think_ we don't need anything special for [`dir_contents_diff`](https://github.com/flutter/engine/blob/b0d3663f439fd97c32bf4d46b9004c97841c43b8/tools/dir_contents_diff), but maybe I'm wrong - I think only the _test_ names are being changed, not the names on disk. /cc @zanderso as well. --- .engine-release.version | 8 + ci/licenses_golden/licenses_flutter | 1 + testing/litetest/lib/src/matchers.dart | 5 + testing/skia_gold_client/README.md | 151 +++++++++++------- .../lib/skia_gold_client.dart | 108 +++++++++++-- testing/skia_gold_client/lib/src/errors.dart | 4 + .../lib/src/release_version.dart | 130 +++++++++++++++ .../test/release_version_test.dart | 68 ++++++++ .../test/skia_gold_client_test.dart | 82 +++++++++- 9 files changed, 483 insertions(+), 74 deletions(-) create mode 100644 .engine-release.version create mode 100644 testing/skia_gold_client/lib/src/release_version.dart create mode 100644 testing/skia_gold_client/test/release_version_test.dart diff --git a/.engine-release.version b/.engine-release.version new file mode 100644 index 0000000000000..dd395bfd21045 --- /dev/null +++ b/.engine-release.version @@ -0,0 +1,8 @@ +# Used to branch and track golden-file rendering of release branches. +# +# See ./testing/skia_gold_client/README.md#release-testing for more information. + +# On the main branch, this should always read 'none'. +# On release branches, this should be the release version such as '3.21' +# (without the quotes). +none diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e040b28546e07..7e4361ef38692 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -41995,6 +41995,7 @@ ORIGIN: ../../../flutter/vulkan/vulkan_window.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/vulkan/vulkan_window.h + ../../../flutter/LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/.clangd +FILE: ../../../flutter/.engine-release.version FILE: ../../../flutter/.pylintrc FILE: ../../../flutter/assets/asset_manager.cc FILE: ../../../flutter/assets/asset_manager.h diff --git a/testing/litetest/lib/src/matchers.dart b/testing/litetest/lib/src/matchers.dart index 5c40eacc093db..ba30a1620cf19 100644 --- a/testing/litetest/lib/src/matchers.dart +++ b/testing/litetest/lib/src/matchers.dart @@ -87,6 +87,11 @@ void throwsRangeError(dynamic d) { Expect.throwsRangeError(d as void Function()); } +/// A [Matcher] that matches functions that throw a [RangeError] when invoked. +void throwsFormatException(dynamic d) { + Expect.throwsFormatException(d as void Function()); +} + /// Gives a [Matcher] that asserts that the value being matched is a [String] /// that contains `s` as a substring. Matcher contains(String s) => (dynamic d) { diff --git a/testing/skia_gold_client/README.md b/testing/skia_gold_client/README.md index 8c4c68e19985c..e63486b13b038 100644 --- a/testing/skia_gold_client/README.md +++ b/testing/skia_gold_client/README.md @@ -1,70 +1,111 @@ -# skia_gold_client +# Skia Gold Client -This package allows to create a Skia gold client in the engine repo. +This package interacts with [Skia Gold][] for uploading and comparing +screenshots. -The client uses the `goldctl` tool on LUCI builders to upload screenshots, -and verify if a new screenshot matches the baseline screenshot. +[skia gold]: https://skia.org/docs/dev/testing/skiagold/ -The web UI is available on https://flutter-engine-gold.skia.org/. +The web UI for the engine is located at . -## Using the client +## Usage -1. In `.ci.yaml`, ensure that the task has a dependency on `goldctl`: +In the simplest case, import the package and establish a working directory: -```yaml -dependencies: [{ "dependency": "goldctl" }] -``` +```dart +import 'dart:io' as io; -2. In the builder `.json` file, ensure the drone has a dependency on `goldctl`: +import 'package:skia_gold_client/skia_gold_client.dart'; -```yaml - "dependencies": [ - { - "dependency": "goldctl", - "version": "git_revision:" - } - ], +void main() async { + // Create a temporary working directory. + final io.Directory tmpDirectory = io.Directory.systemTemp.createTempSync('skia_gold_wd'); + try { + final SkiaGoldClient client = SkiaGoldClient(tmpDirectory); + await client.auth(); + // ... + } finally { + tmpDirectory.deleteSync(recursive: true); + } +} ``` -3. Add dependency in `pubspec.yaml`: +Once you have an authorized instance, use `addImg` to upload a screenshot: -```yaml -dependencies: - # needed for skia_gold_client to avoid a cache miss. - engine_repo_tools: - path: /tools/pkg/engine_repo_tools - skia_gold_client: - path: /testing/skia_gold_client +```dart +await client.addImg( + 'my-screenshot', + io.File('path/to/screenshot.png'), + screenshotSize: 400, // i.e. a 20x20 image +); ``` -4. Use the client: +## Configuring CI -```dart -import 'package:skia_gold_client/skia_gold_client.dart'; +Currently[^1], the client is only available on Flutter Engine's CI platform, and +will fail to authenticate if run elsewhere. -Future main() { - final Directory tmpDirectory = Directory.current.createTempSync('skia_gold_wd'); - final SkiaGoldClient client = SkiaGoldClient( - tmpDirectory, - dimensions: {'': ''}, - ); - - try { - if (SkiaGoldClient.isAvailable()) { - await client.auth(); - - await client.addImg( - '', - File('gold-file.png'), - screenshotSize: 1024, - ); - } - } catch (error) { - // Failed to authenticate or compare pixels. - stderr.write(error.toString()); - rethrow; - } finally { - tmpDirectory.deleteSync(recursive: true); - } -} -``` +To use the client in CI, you'll need to make two changes: + +[^1]: + The `flutter/flutter` repository has a workaround which downloads digests + and does basic local image comparison, but because we have forked the + client and not kept it up-to-date, we cannot use that workaround. Send + a PR or file an issue if you'd like to see this fixed! + +1. **Add a dependency on `goldctl`** + + In your task's configuration in [`.ci.yaml`](../../.ci.yaml) file, add a + dependency on `goldctl`: + + ```diff + # This is just an example. + targets: + - name: Linux linux_android_emulator_tests + properties: + config_name: linux_android_emulator + + dependencies: >- + + [ + + {"dependency": "goldctl", "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd"} + + ] + ``` + +2. **Ensure the builder (i.e. `config_name: {name}`) also has a dependency** + + For example, for `linux_android_emulator`, modify + [`ci/builders/linux_android_emulator.json`](../../ci/builders/linux_android_emulator.json): + + ```json + "dependencies": [ + { + "dependency": "goldctl", + "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd" + } + ] + ``` + +## Release Testing + +> [!NOTE] +> This workflow is a work in progress. Contact @matanlurey for more information. + +When we create a release branch (i.e. for a beta or stable release), all +golden-file tests will have to be regenerated for the new release. This is +because it's possible that the rendering of the engine has changed in a way +that affects the golden files (either due to a bug, or intentionally) as we +apply cherry-picks and other changes to the release branch. + +Fortunately this process is easy and mostly automated. Here's how it works: + +1. Create your release branch, e.g. `flutter-3.21-candidate.1`. +1. Edit [`.engine-release.verison`](../../.engine-release.version) to the new + release version (e.g. `3.21`). +1. Run all the tests, generating new golden files. +1. Bulk triage all of the images as positive using the web UI. + + ![Screenshot](https://github.com/flutter/flutter/assets/168174/a327ffc0-95b3-4d3a-9d36-052e0607a1e5) + +All of the tests will have a unique `_Release_{major}}_{minor}` suffix, so you +can easily filter them in the web UI and they can diverge from the `main` branch +as needed. As cherry-picks are applied to the release branch, the tests should +continue to pass, and the golden files should either _not_ change, or change in +a way that is expected (i.e. fixing a bug). diff --git a/testing/skia_gold_client/lib/skia_gold_client.dart b/testing/skia_gold_client/lib/skia_gold_client.dart index e9d28ff504286..9d14d0116f074 100644 --- a/testing/skia_gold_client/lib/skia_gold_client.dart +++ b/testing/skia_gold_client/lib/skia_gold_client.dart @@ -12,6 +12,7 @@ import 'package:path/path.dart' as path; import 'package:process/process.dart'; import 'src/errors.dart'; +import 'src/release_version.dart'; export 'src/errors.dart' show SkiaGoldProcessError; @@ -22,14 +23,57 @@ const String _kLuciEnvName = 'LUCI_CONTEXT'; const String _skiaGoldHost = 'https://flutter-engine-gold.skia.org'; const String _instance = 'flutter-engine'; -/// A client for uploading image tests and making baseline requests to the -/// Flutter Gold Dashboard. +/// Uploads images and makes baseline requests to Skia Gold. +/// +/// For an example of how to use this class, see `tool/e2e_test.dart`. interface class SkiaGoldClient { /// Creates a [SkiaGoldClient] with the given [workDirectory]. /// - /// [dimensions] allows to add attributes about the environment - /// used to generate the screenshots. - SkiaGoldClient( + /// A set of [dimensions] can be provided to add attributes about the + /// environment used to generate the screenshots, which are treated as keys + /// for the image: + /// + /// ```dart + /// final SkiaGoldClient skiaGoldClient = SkiaGoldClient( + /// someDir, + /// dimensions: { + /// 'platform': 'linux', + /// }, + /// ); + /// ``` + /// + /// The [verbose] flag is intended for use in debugging CI issues, and + /// produces more detailed output that some may find useful, but would be too + /// spammy for regular use. + factory SkiaGoldClient( + io.Directory workDirectory, { + Map? dimensions, + bool verbose = false, + }) { + return SkiaGoldClient.forTesting( + workDirectory, + dimensions: dimensions, + verbose: verbose, + ); + } + + /// Creates a [SkiaGoldClient] for testing. + /// + /// Similar to the default constructor, but allows for dependency injection + /// for testing purposes: + /// + /// - [httpClient] makes requests to Skia Gold to fetch expectations. + /// - [processManager] launches sub-processes. + /// - [stderr] is where output is written for diagnostics. + /// - [environment] is the environment variables for the currently running + /// process, and is used to determine if Skia Gold is available, and whether + /// the current environment is CI, and if so, if it's pre-submit or + /// post-submit. + /// - [engineRoot] is the root of the engine repository, which is used for + /// finding the current commit hash, as well as the location of the + /// `.engine-release.version` file. + @visibleForTesting + SkiaGoldClient.forTesting( this.workDirectory, { this.dimensions, this.verbose = false, @@ -37,10 +81,31 @@ interface class SkiaGoldClient { ProcessManager? processManager, StringSink? stderr, Map? environment, + Engine? engineRoot, }) : httpClient = httpClient ?? io.HttpClient(), process = processManager ?? const LocalProcessManager(), _stderr = stderr ?? io.stderr, - _environment = environment ?? io.Platform.environment; + _environment = environment ?? io.Platform.environment, + _engineRoot = engineRoot ?? Engine.findWithin() { + // Lookup the release version from the engine repository. + final io.File releaseVersionFile = io.File(path.join( + _engineRoot.flutterDir.path, + '.engine-release.version', + )); + + // If the file is not found or cannot be read, we are in an invalid state. + try { + _releaseVersion = ReleaseVersion.parse(releaseVersionFile.readAsStringSync()); + } on FormatException catch (error) { + throw StateError('Failed to parse release version file: $error.'); + } on io.FileSystemException catch (error) { + throw StateError('Failed to read release version file: $error.'); + } + } + + /// The root of the engine repository. + final Engine _engineRoot; + ReleaseVersion? _releaseVersion; /// Whether the client is available and can be used in this environment. static bool isAvailable({ @@ -244,6 +309,14 @@ interface class SkiaGoldClient { /// determined by the [pixelColorDelta] parameter. It's in the range [0.0, /// 1.0] and defaults to 0.01. A value of 0.01 means that 1% of the pixels are /// allowed to be different. + /// + /// ## Release Testing + /// + /// In release branches, we add a unique test suffix to the test name. For + /// example "testName" -> "testName_Release_3_21", based on the version in the + /// `.engine-release.version` file at the root of the engine repository. + /// + /// See <../README.md#release-testing> for more information. Future addImg( String testName, io.File goldenFile, { @@ -252,6 +325,17 @@ interface class SkiaGoldClient { required int screenshotSize, }) async { assert(_isPresubmit || _isPostsubmit); + + // Clean the test name to remove the file extension. + testName = path.basenameWithoutExtension(testName); + + // In release branches, we add a unique test suffix to the test name. + // For example "testName" -> "testName_Release_3_21". + // See ../README.md#release-testing for more information. + if (_releaseVersion case final ReleaseVersion v) { + testName = '${testName}_Release_${v.major}_${v.minor}'; + } + if (_isPresubmit) { await _tryjobAdd(testName, goldenFile, screenshotSize, pixelColorDelta, differentPixelsRate); } @@ -287,7 +371,7 @@ interface class SkiaGoldClient { '--work-dir', _tempPath, '--test-name', - _cleanTestName(testName), + testName, '--png-file', goldenFile.path, // Otherwise post submit will not fail. @@ -391,7 +475,7 @@ interface class SkiaGoldClient { '--work-dir', _tempPath, '--test-name', - _cleanTestName(testName), + testName, '--png-file', goldenFile.path, ..._getMatchingArguments(testName, screenshotSize, pixelDeltaThreshold, differentPixelsRate), @@ -489,7 +573,7 @@ interface class SkiaGoldClient { /// Returns the current commit hash of the engine repository. Future _getCurrentCommit() async { - final String engineCheckout = Engine.findWithin().flutterDir.path; + final String engineCheckout = _engineRoot.flutterDir.path; final io.ProcessResult revParse = await process.run( ['git', 'rev-parse', 'HEAD'], workingDirectory: engineCheckout, @@ -521,12 +605,6 @@ interface class SkiaGoldClient { return json.encode(_getKeys()); } - /// Removes the file extension from the [fileName] to represent the test name - /// properly. - static String _cleanTestName(String fileName) { - return path.basenameWithoutExtension(fileName); - } - /// Returns a list of arguments for initializing a tryjob based on the testing /// environment. List _getCIArguments() { diff --git a/testing/skia_gold_client/lib/src/errors.dart b/testing/skia_gold_client/lib/src/errors.dart index d5590091bf46d..830555229d35b 100644 --- a/testing/skia_gold_client/lib/src/errors.dart +++ b/testing/skia_gold_client/lib/src/errors.dart @@ -1,3 +1,7 @@ +// 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. + /// Skia Gold errors thrown by intepreting process exits and [stdout]/[stderr]. final class SkiaGoldProcessError extends Error { /// Creates a new [SkiaGoldProcessError] from the provided origin. diff --git a/testing/skia_gold_client/lib/src/release_version.dart b/testing/skia_gold_client/lib/src/release_version.dart new file mode 100644 index 0000000000000..a62953e349c60 --- /dev/null +++ b/testing/skia_gold_client/lib/src/release_version.dart @@ -0,0 +1,130 @@ +// 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. + +import 'dart:convert'; + +import 'package:meta/meta.dart'; + +/// Signals that the output of golden files may diverge from `main`. +/// +/// By default, Skia Gold will compare the output of a test to the golden file +/// in the `main` branch. During a release branch, the output of the test may +/// diverge (intentionally or accidentally, i.e. a bug) from the output in +/// `main`. +/// +/// This class signals to Skia Gold to use a unique test name for the release. +@immutable +final class ReleaseVersion { + /// Creates a [ReleaseVersion] with the given [major] and [minor] version. + /// + /// For example, for the `3.21` release: + /// ```dart + /// ReleaseVersion( + /// major: 3, + /// minor: 21, + /// ) + /// ``` + /// + /// Each number must be non-negative. + ReleaseVersion({ + required this.major, + required this.minor, + }) { + RangeError.checkNotNegative(major, 'major'); + RangeError.checkNotNegative(minor, 'minor'); + } + + /// Parses a [ReleaseVersion] from the contents of a `release.version` file. + /// + /// Returns `null` if and only if the version is parsed as the string `none`. + /// + /// The format of the file is plaintext, and any lines that are empty + /// (newline characters only) or start with `#` are ignored. The first line + /// that is not ignored must be in the format `major.minor`, where `major` and + /// `minor` are non-negative integers. + /// + /// For example, the following file contents: + /// ```txt + /// # This is a comment + /// + /// 3.21 + /// ``` + /// + /// ... would parse to `ReleaseVersion(major: 3, minior: 21)`. + /// + /// Throws a [FormatException] if the file contents are not in the expected + /// format (either empty/comments only, or missing a `major.minor` line in + /// the format described in [ReleaseVersion.new]). + static ReleaseVersion? parse(String fileContents) { + bool parsedNone = false; + ReleaseVersion? parsed; + for (final String line in LineSplitter.split(fileContents)) { + final String trimmed = line.trim(); + if (trimmed.isEmpty || trimmed.startsWith('#')) { + continue; + } + if (trimmed == 'none') { + parsedNone = true; + continue; + } + final List parts = trimmed.split('.'); + if (parts.length != 2) { + throw FormatException( + 'Expected "major.minor" format, got "$trimmed"', + fileContents, + ); + } + final int? major = int.tryParse(parts[0]); + final int? minor = int.tryParse(parts[1]); + if (major == null || minor == null) { + throw FormatException( + 'Expected "major.minor", each as an integer, got "$trimmed"', + fileContents, + ); + } + if (parsed != null) { + throw FormatException( + 'Multiple "major.minor" versions found', + fileContents, + ); + } + parsed = ReleaseVersion( + major: major, + minor: minor, + ); + } + if (parsed != null && parsedNone) { + throw FormatException( + 'Both "none" and a "major.minor" version found', + fileContents, + ); + } + if (parsed != null) { + return parsed; + } + if (parsedNone) { + return null; + } + throw FormatException('No "major.minor" version found', fileContents); + } + + /// The major version number. + final int major; + + /// The minor version number. + final int minor; + + @override + bool operator ==(Object other) { + return other is ReleaseVersion && + other.major == major && + other.minor == minor; + } + + @override + int get hashCode => Object.hash(major, minor); + + @override + String toString() => '$major.$minor'; +} diff --git a/testing/skia_gold_client/test/release_version_test.dart b/testing/skia_gold_client/test/release_version_test.dart new file mode 100644 index 0000000000000..72f7e73a31f53 --- /dev/null +++ b/testing/skia_gold_client/test/release_version_test.dart @@ -0,0 +1,68 @@ +// 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. + +import 'package:litetest/litetest.dart'; +import 'package:skia_gold_client/src/release_version.dart'; + +void main() { + test('should accept a major and minor version', () { + final ReleaseVersion version = ReleaseVersion(major: 3, minor: 21); + expect(version.major, equals(3)); + expect(version.minor, equals(21)); + }); + + test('should accept the string "none"', () { + final ReleaseVersion? version = ReleaseVersion.parse('none'); + expect(version, isNull); + }); + + test('should fail on a negative major version', () { + expect(() => ReleaseVersion(major: -1, minor: 0), throwsRangeError); + }); + + test('should fail on a negative minor version', () { + expect(() => ReleaseVersion(major: 0, minor: -1), throwsRangeError); + }); + + test('should parse a release version from a file', () { + final ReleaseVersion version = ReleaseVersion.parse('3.21')!; + expect(version.major, equals(3)); + expect(version.minor, equals(21)); + }); + + test('should ignore comments and empty lines', () { + final ReleaseVersion version = ReleaseVersion.parse([ + '# This is a comment', + '', + '3.21', + '', + ].join('\n'))!; + expect(version.major, equals(3)); + expect(version.minor, equals(21)); + }); + + test('should fail on a missing version line', () { + expect(() => ReleaseVersion.parse(''), throwsFormatException); + }); + + test('should fail on a malformed version line', () { + expect(() => ReleaseVersion.parse('3.21.0'), throwsFormatException); + }); + + test('should fail on a non-integer major version', () { + expect(() => ReleaseVersion.parse('a.21'), throwsFormatException); + }); + + test('should fail on a non-integer minor version', () { + expect(() => ReleaseVersion.parse('3.b'), throwsFormatException); + }); + + test('should fail on multiple version lines', () { + expect(() => ReleaseVersion.parse('3.21\n3.22'), throwsFormatException); + }); + + test('should fail if both "none" and a version are present', () { + expect(() => ReleaseVersion.parse('none\n3.21'), throwsFormatException); + }); +} diff --git a/testing/skia_gold_client/test/skia_gold_client_test.dart b/testing/skia_gold_client/test/skia_gold_client_test.dart index 1f91d8a35231a..b3265866da3da 100644 --- a/testing/skia_gold_client/test/skia_gold_client_test.dart +++ b/testing/skia_gold_client/test/skia_gold_client_test.dart @@ -7,10 +7,12 @@ import 'dart:convert'; import 'dart:io' as io; import 'dart:typed_data'; +import 'package:engine_repo_tools/engine_repo_tools.dart'; import 'package:litetest/litetest.dart'; import 'package:path/path.dart' as p; import 'package:process_fakes/process_fakes.dart'; import 'package:skia_gold_client/skia_gold_client.dart'; +import 'package:skia_gold_client/src/release_version.dart'; void main() { /// A mock commit hash that is used to simulate a successful git call. @@ -44,13 +46,15 @@ void main() { SkiaGoldClient createClient( _TestFixture fixture, { required Map environment, + ReleaseVersion? engineVersion, Map? dimensions, bool verbose = false, io.ProcessResult Function(List command) onRun = _runUnhandled, }) { - return SkiaGoldClient( + return SkiaGoldClient.forTesting( fixture.workDirectory, dimensions: dimensions, + engineRoot: Engine.fromSrcPath(fixture.engineSrcDir.path), httpClient: fixture.httpClient, processManager: FakeProcessManager( onRun: onRun, @@ -237,6 +241,58 @@ void main() { } }); + test('addImg [pre-submit] executes successfully with a release version', () async { + // Adds a suffix of "_Release_3_21" to the test name. + final _TestFixture fixture = _TestFixture( + // Creates a file called "engine/src/fluter/.engine-release.version" with the contents "3.21". + engineVersion: ReleaseVersion( + major: 3, + minor: 21, + ), + ); + try { + final SkiaGoldClient client = createClient( + fixture, + environment: presubmitEnv, + onRun: (List command) { + if (command case ['git', ...]) { + return io.ProcessResult(0, 0, mockCommitHash, ''); + } + if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + return io.ProcessResult(0, 0, '', ''); + } + expect(command, [ + 'python tools/goldctl.py', + 'imgtest', + 'add', + '--work-dir', + p.join(fixture.workDirectory.path, 'temp'), + '--test-name', + // This is the significant change. + 'test-name_Release_3_21', + '--png-file', + p.join(fixture.workDirectory.path, 'temp', 'golden.png'), + '--add-test-optional-key', + 'image_matching_algorithm:fuzzy', + '--add-test-optional-key', + 'fuzzy_max_different_pixels:10', + '--add-test-optional-key', + 'fuzzy_pixel_delta_threshold:0', + ]); + return io.ProcessResult(0, 0, '', ''); + }, + ); + + await client.addImg( + 'test-name.foo', + io.File(p.join(fixture.workDirectory.path, 'temp', 'golden.png')), + screenshotSize: 1000, + ); + } finally { + fixture.dispose(); + } + }); + test('addImg [pre-submit] executes successfully with verbose logging', () async { final _TestFixture fixture = _TestFixture(); try { @@ -536,14 +592,32 @@ void main() { } final class _TestFixture { - _TestFixture(); + _TestFixture({ + ReleaseVersion? engineVersion, + }) { + workDirectory = rootDirectory.createTempSync('working'); + + // Create the engine/src directory. + engineSrcDir = io.Directory(p.join(rootDirectory.path, 'engine', 'src')); + engineSrcDir.createSync(recursive: true); + + // Create a .engine-release.version file in the engine root. + final io.Directory flutterDir = io.Directory(p.join(engineSrcDir.path, 'flutter')); + flutterDir.createSync(recursive: true); + + final String version = engineVersion?.toString() ?? 'none'; + io.File(p.join(flutterDir.path, '.engine-release.version')).writeAsStringSync(version); + } + + final io.Directory rootDirectory = io.Directory.systemTemp.createTempSync('skia_gold_client_test'); + late final io.Directory workDirectory; + late final io.Directory engineSrcDir; - final io.Directory workDirectory = io.Directory.systemTemp.createTempSync('skia_gold_client_test'); final _FakeHttpClient httpClient = _FakeHttpClient(); final StringSink outputSink = StringBuffer(); void dispose() { - workDirectory.deleteSync(recursive: true); + rootDirectory.deleteSync(recursive: true); } } From 8480145cc39dde90d56e98e2a74571628371f08f Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 11:44:04 -0700 Subject: [PATCH 23/49] Add a minimal example of using `package:test`. (#51726) Work towards https://github.com/flutter/flutter/issues/133569. This PR is a proof of concept that shows we're able to use `package:test` in `flutter/engine` instead of `package:litetest`. I think it also shows that, if we're going to continue to vend dependencies this way, we might want to re-think our strategy in terms of using `pub` as a management tool - it's quite unwieldy already. For example, here is every `pubspec.yaml` file in the repo: ```sh $ find . -name 'pubspec.yaml' -exec sh -c 'echo "$0 $(wc -l < "$0")"' {} \; # Some files omitted in third_party or similar. ./impeller/tessellator/dart/pubspec.yaml 11 ./tools/const_finder/pubspec.yaml 35 ./tools/api_check/pubspec.yaml 90 ./tools/build_bucket_golden_scraper/pubspec.yaml 47 ./tools/licenses/pubspec.yaml 53 ./tools/path_ops/dart/pubspec.yaml 26 ./tools/engine_tool/pubspec.yaml 76 ./tools/dir_contents_diff/pubspec.yaml 19 ./tools/compare_goldens/pubspec.yaml 3 ./tools/golden_tests_harvester/pubspec.yaml 55 ./tools/gen_web_locale_keymap/pubspec.yaml 37 ./tools/githooks/pubspec.yaml 63 ./tools/android_lint/pubspec.yaml 35 ./tools/clang_tidy/pubspec.yaml 76 ./tools/pkg/engine_repo_tools/pubspec.yaml 41 ./tools/pkg/process_fakes/pubspec.yaml 36 ./tools/pkg/engine_build_configs/pubspec.yaml 73 ./tools/pkg/git_repo_tools/pubspec.yaml 60 ./tools/header_guard_check/pubspec.yaml 70 ./sky/packages/sky_engine/pubspec.yaml 8 ./shell/vmservice/pubspec.yaml 8 ./ci/pubspec.yaml 57 ./testing/benchmark/pubspec.yaml 77 ./testing/skia_gold_client/pubspec.yaml 66 ./testing/pkg_test_demo/pubspec.yaml 116 ./testing/smoke_test_failure/pubspec.yaml 31 ./testing/dart/pubspec.yaml 71 ./testing/android_background_image/pubspec.yaml 22 ./testing/litetest/pubspec.yaml 33 ./testing/symbols/pubspec.yaml 24 ./testing/scenario_app/pubspec.yaml 67 ./web_sdk/web_engine_tester/pubspec.yaml 14 ./web_sdk/web_test_utils/pubspec.yaml 22 ./web_sdk/pubspec.yaml 60 ./lib/snapshot/pubspec.yaml 8 ./lib/gpu/pubspec.yaml 14 ./lib/web_ui/pubspec.yaml 60 ./flutter_frontend_server/pubspec.yaml 39 ``` I'll file a follow-up issue to discuss pub-package management in the engine. --- DEPS | 11 +- ci/licenses.sh | 2 +- ci/licenses_golden/excluded_files | 28 ++ ci/licenses_golden/licenses_flutter | 380 ++++++++++++++++++- testing/pkg_test_demo/README.md | 32 ++ testing/pkg_test_demo/pubspec.yaml | 117 ++++++ testing/pkg_test_demo/test/example_test.dart | 17 + testing/run_tests.py | 1 + tools/pub_get_offline.py | 2 + 9 files changed, 587 insertions(+), 3 deletions(-) create mode 100644 testing/pkg_test_demo/README.md create mode 100644 testing/pkg_test_demo/pubspec.yaml create mode 100644 testing/pkg_test_demo/test/example_test.dart diff --git a/DEPS b/DEPS index baff977dd07eb..ea5647ed443d2 100644 --- a/DEPS +++ b/DEPS @@ -336,7 +336,7 @@ deps = { Var('flutter_git') + '/third_party/yapf' + '@' + '212c5b5ad8e172d2d914ae454c121c89cccbcb35', 'src/flutter/third_party/boringssl/src': - 'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('dart_boringssl_rev'), + 'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('dart_boringssl_rev'), 'src/flutter/third_party/perfetto': Var('flutter_git') + "/third_party/perfetto" + '@' + Var('dart_perfetto_rev'), @@ -695,6 +695,9 @@ deps = { 'src/flutter/third_party/pkg/archive': Var('chromium_git') + '/external/github.com/brendan-duncan/archive.git' + '@' + '9de7a0544457c6aba755ccb65abb41b0dc1db70d', # 3.1.2 + 'src/flutter/third_party/pkg/coverage': + Var('flutter_git') + '/third_party/coverage.git' + '@' + 'bb0ab721ee4ceef1abfa413d8d6fd46013b583b9', # 1.7.2 + 'src/flutter/third_party/pkg/equatable': Var('flutter_git') + '/third_party/equatable.git' + '@' + '2117551ff3054f8edb1a58f63ffe1832a8d25623', # 2.0.5 @@ -707,6 +710,12 @@ deps = { 'src/flutter/third_party/pkg/googleapis': Var('flutter_git') + '/third_party/googleapis.dart.git' + '@' + '526011f56d98eab183cc6075ee1392e8303e43e2', # various + 'src/flutter/third_party/pkg/io': + Var('flutter_git') + '/third_party/io.git' + '@' + '997a6243aad20af4238147d9ec00bf638b9169af', # 1.0.5-wip + + 'src/flutter/third_party/pkg/node_preamble': + Var('flutter_git') + '/third_party/node_preamble.dart.git' + '@' + '47245865175929ec452d8058e563c267b64c3d64', # 2.0.2 + 'src/flutter/third_party/pkg/platform': Var('dart_git') + '/platform.dart' + '@' + '1ffad63428bbd1b3ecaa15926bacfb724023648c', # 3.1.0 diff --git a/ci/licenses.sh b/ci/licenses.sh index c971050b67cf4..1f59876fe6b94 100755 --- a/ci/licenses.sh +++ b/ci/licenses.sh @@ -174,7 +174,7 @@ function verify_licenses() ( local actualLicenseCount actualLicenseCount="$(tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9')" - local expectedLicenseCount=879 # When changing this number: Update the error message below as well describing the newly expected license types. + local expectedLicenseCount=888 # When changing this number: Update the error message below as well describing the newly expected license types. if [[ $actualLicenseCount -ne $expectedLicenseCount ]]; then echo "=============================== ERROR ===============================" diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index a3b47fc20bb3f..429b126fbf6fa 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -2155,10 +2155,38 @@ ../../../flutter/third_party/perfetto/ui/src/plugins/dev.perfetto.LargeScreensPerf/OWNERS ../../../flutter/third_party/perfetto/ui/src/test ../../../flutter/third_party/pkg/archive +../../../flutter/third_party/pkg/coverage/.git +../../../flutter/third_party/pkg/coverage/.github +../../../flutter/third_party/pkg/coverage/.gitignore +../../../flutter/third_party/pkg/coverage/AUTHORS +../../../flutter/third_party/pkg/coverage/CHANGELOG.md +../../../flutter/third_party/pkg/coverage/PATENTS +../../../flutter/third_party/pkg/coverage/README.md +../../../flutter/third_party/pkg/coverage/analysis_options.yaml +../../../flutter/third_party/pkg/coverage/benchmark/.gitignore +../../../flutter/third_party/pkg/coverage/pubspec.yaml +../../../flutter/third_party/pkg/coverage/test ../../../flutter/third_party/pkg/equatable ../../../flutter/third_party/pkg/flutter_packages ../../../flutter/third_party/pkg/gcloud ../../../flutter/third_party/pkg/googleapis +../../../flutter/third_party/pkg/io/.git +../../../flutter/third_party/pkg/io/.github +../../../flutter/third_party/pkg/io/.gitignore +../../../flutter/third_party/pkg/io/AUTHORS +../../../flutter/third_party/pkg/io/CHANGELOG.md +../../../flutter/third_party/pkg/io/README.md +../../../flutter/third_party/pkg/io/analysis_options.yaml +../../../flutter/third_party/pkg/io/example +../../../flutter/third_party/pkg/io/pubspec.yaml +../../../flutter/third_party/pkg/io/test +../../../flutter/third_party/pkg/node_preamble/.git +../../../flutter/third_party/pkg/node_preamble/.gitignore +../../../flutter/third_party/pkg/node_preamble/CHANGELOG.md +../../../flutter/third_party/pkg/node_preamble/README.md +../../../flutter/third_party/pkg/node_preamble/example +../../../flutter/third_party/pkg/node_preamble/package.json +../../../flutter/third_party/pkg/node_preamble/pubspec.yaml ../../../flutter/third_party/pkg/platform ../../../flutter/third_party/pkg/process ../../../flutter/third_party/pkg/process_runner diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7e4361ef38692..a08d4853afa14 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -35030,6 +35030,42 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/bin/format_coverage.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/bin/format_coverage.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: khronos ORIGIN: ../../../flutter/third_party/angle/src/third_party/khronos/GL/wglext.h @@ -35447,6 +35483,54 @@ use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/bin/collect_coverage.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/coverage.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/collect.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/formatter.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/hitmap.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/resolver.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/util.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/bin/collect_coverage.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/coverage.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/collect.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/formatter.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/hitmap.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/resolver.dart +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/util.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: glslang ORIGIN: ../../../flutter/third_party/vulkan-deps/glslang/src/SPIRV/GLSL.ext.AMD.h @@ -35621,6 +35705,64 @@ FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/node_preamble/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/node_preamble/lib/preamble.dart +FILE: ../../../flutter/third_party/pkg/node_preamble/lib/preamble.js +FILE: ../../../flutter/third_party/pkg/node_preamble/lib/preamble.min.js +FILE: ../../../flutter/third_party/pkg/node_preamble/tool/minify.js +FILE: ../../../flutter/third_party/pkg/node_preamble/yarn.lock +---------------------------------------------------------------------------------------------------- +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/err_data.c @@ -35725,6 +35867,42 @@ use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/run_and_collect.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/run_and_collect.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: fiat ORIGIN: ../../../flutter/third_party/boringssl/src/third_party/fiat/LICENSE @@ -35978,6 +36156,42 @@ OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/bin/run_and_collect.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/bin/run_and_collect.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/hrss/asm/poly_rq_mul.S @@ -36491,6 +36705,42 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/lib/src/chrome.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/lib/src/chrome.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: etc_decoder ORIGIN: ../../../flutter/third_party/angle/src/libANGLE/renderer/vulkan/shaders/src/third_party/etc_decoder/etc_decoder.h @@ -36791,6 +37041,46 @@ OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/coverage/benchmark/many_isolates.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/benchmark/run_benchmarks.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/coverage/bin/test_with_coverage.dart + ../../../flutter/third_party/pkg/coverage/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/coverage/benchmark/many_isolates.dart +FILE: ../../../flutter/third_party/pkg/coverage/benchmark/run_benchmarks.dart +FILE: ../../../flutter/third_party/pkg/coverage/bin/test_with_coverage.dart +---------------------------------------------------------------------------------------------------- +Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: boringssl ORIGIN: ../../../flutter/third_party/boringssl/src/crypto/cpu_aarch64_sysreg.c @@ -47022,6 +47312,58 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/io/lib/ansi.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/io.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/ansi_code.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/copy_path.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/exit_code.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/permissions.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/process_manager.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/shared_stdin.dart + ../../../flutter/third_party/pkg/io/LICENSE +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/shell_words.dart + ../../../flutter/third_party/pkg/io/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/io/lib/ansi.dart +FILE: ../../../flutter/third_party/pkg/io/lib/io.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/ansi_code.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/copy_path.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/exit_code.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/permissions.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/process_manager.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/shared_stdin.dart +FILE: ../../../flutter/third_party/pkg/io/lib/src/shell_words.dart +---------------------------------------------------------------------------------------------------- +Copyright 2017, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: libwebp ORIGIN: ../../../flutter/third_party/libwebp/src/dsp/cost_neon.c + ../../../flutter/third_party/libwebp/COPYING @@ -49655,6 +49997,42 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: pkg +ORIGIN: ../../../flutter/third_party/pkg/io/lib/src/charcodes.dart + ../../../flutter/third_party/pkg/io/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/pkg/io/lib/src/charcodes.dart +---------------------------------------------------------------------------------------------------- +Copyright 2021, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: angle ORIGIN: ../../../flutter/third_party/angle/src/libANGLE/renderer/vulkan/linux/wayland/DisplayVkWayland.cpp + ../../../flutter/third_party/angle/LICENSE @@ -67154,4 +67532,4 @@ Disclaimer and license similar terms. ==================================================================================================== -Total license count: 879 +Total license count: 888 diff --git a/testing/pkg_test_demo/README.md b/testing/pkg_test_demo/README.md new file mode 100644 index 0000000000000..85f548c9d52b4 --- /dev/null +++ b/testing/pkg_test_demo/README.md @@ -0,0 +1,32 @@ +# Demo of `package:test` with `DEPS`-vendored packages + +Historically, `flutter/engine` used a homegrown test framework, +[`package:litetest`](../litetest/) to avoid depending on the unwieldy set of +dependencies that `package:test` brings in. However, `package:test` is now +vendored in `DEPS` (used by the Dart SDK).' + +This demo shows that: + +- It's possible to use `package:test` with entirely local dependencies. +- The functionality of `package:test` (such as filtering, IDE integration, etc.) + is available. + +See for details. + +## Usage + +Navigate to this directory: + +```sh +cd testing/pkg_test_demo +``` + +And run the tests using `dart test`[^1]: + +```sh +dart test +``` + +[^1]: + In practice, you'll want to use the `dart` binary that is vendored in the + pre-built SDK. diff --git a/testing/pkg_test_demo/pubspec.yaml b/testing/pkg_test_demo/pubspec.yaml new file mode 100644 index 0000000000000..aca16b980b8a1 --- /dev/null +++ b/testing/pkg_test_demo/pubspec.yaml @@ -0,0 +1,117 @@ +# 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. + +name: pkg_test_demo +publish_to: none + +# Do not add any dependencies that require more than what is provided in +# //third_party/dart/pkg or //third_party/dart/third_party/pkg. + +# If you do add packages here, make sure you can run `pub get --offline`, and +# check the .packages and .package_config to make sure all the paths are +# relative to this directory into //third_party/dart + +environment: + sdk: '>=3.2.0-0 <4.0.0' + +dev_dependencies: + test: + +dependency_overrides: + _fe_analyzer_shared: + path: ../../../third_party/dart/pkg/_fe_analyzer_shared + _macros: + path: ../../../third_party/dart/pkg/_macros + analyzer: + path: ../../../third_party/dart/pkg/analyzer + args: + path: ../../../third_party/dart/third_party/pkg/args + async: + path: ../../../third_party/dart/third_party/pkg/async + boolean_selector: + path: ../../../third_party/dart/third_party/pkg/boolean_selector + collection: + path: ../../../third_party/dart/third_party/pkg/collection + convert: + path: ../../../third_party/dart/third_party/pkg/convert + coverage: + path: ../../third_party/pkg/coverage + crypto: + path: ../../../third_party/dart/third_party/pkg/crypto + file: + path: ../../../third_party/dart/third_party/pkg/file/packages/file + frontend_server_client: + path: ../../../third_party/dart/third_party/pkg/webdev/frontend_server_client + glob: + path: ../../../third_party/dart/third_party/pkg/glob + http_multi_server: + path: ../../../third_party/dart/third_party/pkg/http_multi_server + http_parser: + path: ../../../third_party/dart/third_party/pkg/http_parser + io: + path: ../../third_party/pkg/io + js: + path: ../../../third_party/dart/pkg/js + logging: + path: ../../../third_party/dart/third_party/pkg/logging + macros: + path: ../../../third_party/dart/pkg/macros + matcher: + path: ../../../third_party/dart/third_party/pkg/matcher + meta: + path: ../../../third_party/dart/pkg/meta + mime: + path: ../../../third_party/dart/third_party/pkg/mime + node_preamble: + path: ../../third_party/pkg/node_preamble + package_config: + path: ../../../third_party/dart/third_party/pkg/package_config + path: + path: ../../../third_party/dart/third_party/pkg/path + pool: + path: ../../../third_party/dart/third_party/pkg/pool + pub_semver: + path: ../../../third_party/dart/third_party/pkg/pub_semver + shelf: + path: ../../../third_party/dart/third_party/pkg/shelf/pkgs/shelf + shelf_packages_handler: + path: ../../../third_party/dart/third_party/pkg/shelf/pkgs/shelf_packages_handler + shelf_static: + path: ../../../third_party/dart/third_party/pkg/shelf/pkgs/shelf_static + shelf_web_socket: + path: ../../../third_party/dart/third_party/pkg/shelf/pkgs/shelf_web_socket + source_map_stack_trace: + path: ../../../third_party/dart/third_party/pkg/source_map_stack_trace + source_maps: + path: ../../../third_party/dart/third_party/pkg/source_maps + source_span: + path: ../../../third_party/dart/third_party/pkg/source_span + stack_trace: + path: ../../../third_party/dart/third_party/pkg/stack_trace + stream_channel: + path: ../../../third_party/dart/third_party/pkg/stream_channel + string_scanner: + path: ../../../third_party/dart/third_party/pkg/string_scanner + term_glyph: + path: ../../../third_party/dart/third_party/pkg/term_glyph + test: + path: ../../../third_party/dart/third_party/pkg/test/pkgs/test + test_api: + path: ../../../third_party/dart/third_party/pkg/test/pkgs/test_api + test_core: + path: ../../../third_party/dart/third_party/pkg/test/pkgs/test_core + typed_data: + path: ../../../third_party/dart/third_party/pkg/typed_data + vm_service: + path: ../../../third_party/dart/pkg/vm_service + watcher: + path: ../../../third_party/dart/third_party/pkg/watcher + web: + path: ../../../third_party/dart/third_party/pkg/web + web_socket_channel: + path: ../../../third_party/dart/third_party/pkg/web_socket_channel + webkit_inspection_protocol: + path: ../../../third_party/dart/third_party/pkg/webkit_inspection_protocol + yaml: + path: ../../../third_party/dart/third_party/pkg/yaml diff --git a/testing/pkg_test_demo/test/example_test.dart b/testing/pkg_test_demo/test/example_test.dart new file mode 100644 index 0000000000000..01343d549eb58 --- /dev/null +++ b/testing/pkg_test_demo/test/example_test.dart @@ -0,0 +1,17 @@ +// 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. + +import 'package:test/test.dart'; + +void main() { + test('String.split() splits the string on the delimiter', () { + const String string = 'foo,bar,baz'; + expect(string.split(','), equals(['foo', 'bar', 'baz'])); + }); + + test('String.trim() removes surrounding whitespace', () { + const String string = ' foo '; + expect(string.trim(), equals('foo')); + }); +} diff --git a/testing/run_tests.py b/testing/run_tests.py index 25af03c2eb3b1..25040a58aa97a 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -937,6 +937,7 @@ def build_dart_host_test_list(build_dir): ], ), (os.path.join('flutter', 'testing', 'litetest'), []), + (os.path.join('flutter', 'testing', 'pkg_test_demo'), []), (os.path.join('flutter', 'testing', 'skia_gold_client'), []), (os.path.join('flutter', 'testing', 'scenario_app'), []), ( diff --git a/tools/pub_get_offline.py b/tools/pub_get_offline.py index f77e59d7d9577..a5b70a1ba9fa9 100644 --- a/tools/pub_get_offline.py +++ b/tools/pub_get_offline.py @@ -26,6 +26,7 @@ os.path.join(ENGINE_DIR, 'testing', 'benchmark'), os.path.join(ENGINE_DIR, 'testing', 'dart'), os.path.join(ENGINE_DIR, 'testing', 'litetest'), + os.path.join(ENGINE_DIR, 'testing', 'pkg_test_demo'), os.path.join(ENGINE_DIR, 'testing', 'scenario_app'), os.path.join(ENGINE_DIR, 'testing', 'skia_gold_client'), os.path.join(ENGINE_DIR, 'testing', 'smoke_test_failure'), @@ -92,6 +93,7 @@ def check_package(package): os.path.join(ENGINE_DIR, 'shell', 'platform', 'fuchsia'), os.path.join(ENGINE_DIR, 'shell', 'vmservice'), os.path.join(ENGINE_DIR, 'sky', 'packages'), + os.path.join(ENGINE_DIR, 'testing', 'pkg_test_demo'), os.path.join(ENGINE_DIR, 'third_party'), os.path.join(ENGINE_DIR, 'web_sdk'), ] From 32c9dab552f0a0742feb113d986773a67dac196a Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 29 Mar 2024 11:50:35 -0700 Subject: [PATCH 24/49] Turn struct half leading in canvaskit kitchensink test back on (#50707) Undo https://github.com/flutter/engine/pull/50617 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- lib/web_ui/test/canvaskit/canvaskit_api_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 69d9f6bf85967..bc7eec8660b17 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1596,7 +1596,7 @@ void _paragraphTests() { ..weight = canvasKit.FontWeight.Bold) ..fontSize = 72 ..heightMultiplier = 1.5 - ..halfLeading = false + ..halfLeading = true ..leading = 0 ..strutEnabled = true ..forceStrutHeight = false; @@ -1673,7 +1673,7 @@ void _paragraphTests() { expect(actual, within(distance: actual / 100, from: expected)); } - expectAlmost(paragraph.getAlphabeticBaseline(), 85.5); + expectAlmost(paragraph.getAlphabeticBaseline(), 78.6); expect(paragraph.didExceedMaxLines(), isFalse); expectAlmost(paragraph.getHeight(), 108); expectAlmost(paragraph.getIdeographicBaseline(), 108); @@ -1699,7 +1699,7 @@ void _paragraphTests() { expectAlmost(lineMetrics.ascent, 55.6); expectAlmost(lineMetrics.descent, 14.8); expect(lineMetrics.isHardBreak, isTrue); - expectAlmost(lineMetrics.baseline, 85.5); + expectAlmost(lineMetrics.baseline, 78.6); expectAlmost(lineMetrics.height, 108); expectAlmost(lineMetrics.left, 2.5); expectAlmost(lineMetrics.width, 263); From 18acc3eb184751a917a745a48879d7ab0c4ce227 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 29 Mar 2024 13:00:05 -0700 Subject: [PATCH 25/49] [macOS] Move to new present callback (#51436) Migrates the macOS embedder to the new present callback which includes a `view_id` value. Not much can be tested, since this doesn't change any features, nor add any features without the ability to add a view. But I added a test to verify that rendering to an unknown view is a graceful no-op. Design doc: https://flutter.dev/go/multi-view-embedder-apis Part of https://github.com/flutter/flutter/issues/144810 Part of https://github.com/flutter/flutter/issues/142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../macos/framework/Source/FlutterEngine.mm | 12 ++--- .../framework/Source/FlutterEngineTest.mm | 51 ++++++++++++++++++- .../Source/fixtures/flutter_desktop_test.dart | 4 ++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 56419b18a661c..f354a23675952 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -847,15 +847,9 @@ - (FlutterCompositor*)createFlutterCompositor { void* user_data // ) { return true; }; - _compositor.present_layers_callback = [](const FlutterLayer** layers, // - size_t layers_count, // - void* user_data // - ) { - // TODO(dkwingsmt): This callback only supports single-view, therefore it - // only operates on the implicit view. To support multi-view, we need a new - // callback that also receives a view ID. - return reinterpret_cast(user_data)->Present(kFlutterImplicitViewId, - layers, layers_count); + _compositor.present_view_callback = [](const FlutterPresentViewInfo* info) { + return reinterpret_cast(info->user_data) + ->Present(info->view_id, info->layers, info->layers_count); }; _compositor.avoid_backing_store_cache = true; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 7b081318148d8..b1d4cfb591f67 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -535,7 +535,56 @@ @implementation MockableFlutterEngine // TODO(gw280): add support for screenshot tests in this test harness [engine shutDownEngine]; -} // namespace flutter::testing +} + +TEST_F(FlutterEngineTest, CompositorIgnoresUnknownView) { + FlutterEngine* engine = GetFlutterEngine(); + auto original_init = engine.embedderAPI.Initialize; + ::FlutterCompositor compositor; + engine.embedderAPI.Initialize = MOCK_ENGINE_PROC( + Initialize, ([&compositor, &original_init]( + size_t version, const FlutterRendererConfig* config, + const FlutterProjectArgs* args, void* user_data, auto engine_out) { + compositor = *args->compositor; + return original_init(version, config, args, user_data, engine_out); + })); + + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + [viewController loadView]; + + EXPECT_TRUE([engine runWithEntrypoint:@"empty"]); + + FlutterBackingStoreConfig config = { + .struct_size = sizeof(FlutterBackingStoreConfig), + .size = FlutterSize{10, 10}, + }; + FlutterBackingStore backing_store = {}; + EXPECT_NE(compositor.create_backing_store_callback, nullptr); + EXPECT_TRUE( + compositor.create_backing_store_callback(&config, &backing_store, compositor.user_data)); + + FlutterLayer layer{ + .type = kFlutterLayerContentTypeBackingStore, + .backing_store = &backing_store, + }; + std::vector layers = {&layer}; + + FlutterPresentViewInfo info = { + .struct_size = sizeof(FlutterPresentViewInfo), + .view_id = 123, + .layers = const_cast(layers.data()), + .layers_count = 1, + .user_data = compositor.user_data, + }; + EXPECT_NE(compositor.present_view_callback, nullptr); + EXPECT_FALSE(compositor.present_view_callback(&info)); + EXPECT_TRUE(compositor.collect_backing_store_callback(&backing_store, compositor.user_data)); + + (void)viewController; + [engine shutDownEngine]; +} TEST_F(FlutterEngineTest, DartEntrypointArguments) { NSString* fixtures = @(flutter::testing::GetFixturesPath()); diff --git a/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart b/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart index 835588ff354ac..7a9a69db73de7 100644 --- a/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart +++ b/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart @@ -12,6 +12,10 @@ external void signalNativeTest(); void main() { } +@pragma('vm:entry-point') +void empty() { +} + /// Notifies the test of a string value. /// /// This is used to notify the native side of the test of a string value from From 2d53384121e0ef2c395836981c38a70920c35f51 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:00:40 -0700 Subject: [PATCH 26/49] [Impeller] split out aiks blend tests (#51780) ## 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] and the [C++, Objective-C, Java style guides]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- ci/licenses_golden/excluded_files | 1 + impeller/aiks/BUILD.gn | 1 + impeller/aiks/aiks_blend_unittests.cc | 525 ++++++++++++++++++++++++++ impeller/aiks/aiks_unittests.cc | 507 +------------------------ 4 files changed, 528 insertions(+), 506 deletions(-) create mode 100644 impeller/aiks/aiks_blend_unittests.cc diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 429b126fbf6fa..8b9f6e7ad663f 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -124,6 +124,7 @@ ../../../flutter/impeller/.clang-format ../../../flutter/impeller/.gitignore ../../../flutter/impeller/README.md +../../../flutter/impeller/aiks/aiks_blend_unittests.cc ../../../flutter/impeller/aiks/aiks_blur_unittests.cc ../../../flutter/impeller/aiks/aiks_gradient_unittests.cc ../../../flutter/impeller/aiks/aiks_path_unittests.cc diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index 10b0a57c79f5e..0fc2354a1dd2f 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -85,6 +85,7 @@ impeller_component("context_spy") { template("aiks_unittests_component") { target_name = invoker.target_name predefined_sources = [ + "aiks_blend_unittests.cc", "aiks_blur_unittests.cc", "aiks_gradient_unittests.cc", "aiks_path_unittests.cc", diff --git a/impeller/aiks/aiks_blend_unittests.cc b/impeller/aiks/aiks_blend_unittests.cc new file mode 100644 index 0000000000000..b94bd5be6e453 --- /dev/null +++ b/impeller/aiks/aiks_blend_unittests.cc @@ -0,0 +1,525 @@ +// 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 "flutter/impeller/aiks/aiks_unittests.h" + +#include "flutter/testing/testing.h" +#include "impeller/aiks/canvas.h" + +//////////////////////////////////////////////////////////////////////////////// +// This is for tests of Canvas that are interested the results of rendering +// blends. +//////////////////////////////////////////////////////////////////////////////// + +namespace impeller { +namespace testing { + +TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer) { + Canvas canvas; + + Rect layer_rect = Rect::MakeXYWH(0, 0, 500, 500); + canvas.ClipRect(layer_rect); + + canvas.SaveLayer( + { + .color_filter = ColorFilter::MakeBlend(BlendMode::kDifference, + Color(0, 1, 0, 0.5)), + }, + layer_rect); + + Paint paint; + canvas.DrawPaint({.color = Color::Black()}); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 300, 300), + {.color = Color::White()}); + canvas.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) { + Canvas canvas; + Paint paint; + + paint.color = Color::Red(); + canvas.DrawPaint(paint); + + paint.blend_mode = BlendMode::kSourceOver; + canvas.SaveLayer(paint); + + paint.color = Color::White(); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); + + paint.blend_mode = BlendMode::kSource; + canvas.SaveLayer(paint); + + paint.color = Color::Blue(); + canvas.DrawRect(Rect::MakeXYWH(200, 200, 200, 200), paint); + + canvas.Restore(); + canvas.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanDrawPaintWithAdvancedBlend) { + Canvas canvas; + canvas.Scale(Vector2(0.2, 0.2)); + canvas.DrawPaint({.color = Color::MediumTurquoise()}); + canvas.DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5), + .blend_mode = BlendMode::kHue}); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, DrawPaintWithAdvancedBlendOverFilter) { + Paint filtered = { + .color = Color::Black(), + .mask_blur_descriptor = + Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Sigma(60), + }, + }; + + Canvas canvas; + canvas.DrawPaint({.color = Color::White()}); + canvas.DrawCircle({300, 300}, 200, filtered); + canvas.DrawPaint({.color = Color::Green(), .blend_mode = BlendMode::kScreen}); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, DrawAdvancedBlendPartlyOffscreen) { + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + std::vector stops = {0.0, 1.0}; + + Paint paint = { + .color_source = ColorSource::MakeLinearGradient( + {0, 0}, {100, 100}, std::move(colors), std::move(stops), + Entity::TileMode::kRepeat, Matrix::MakeScale(Vector3(0.3, 0.3, 0.3))), + .blend_mode = BlendMode::kLighten, + }; + + Canvas canvas; + canvas.DrawPaint({.color = Color::Blue()}); + canvas.Scale(Vector2(2, 2)); + canvas.ClipRect(Rect::MakeLTRB(0, 0, 200, 200)); + canvas.DrawCircle({100, 100}, 100, paint); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, PaintBlendModeIsRespected) { + Paint paint; + Canvas canvas; + // Default is kSourceOver. + paint.color = Color(1, 0, 0, 0.5); + canvas.DrawCircle(Point(150, 200), 100, paint); + paint.color = Color(0, 1, 0, 0.5); + canvas.DrawCircle(Point(250, 200), 100, paint); + + paint.blend_mode = BlendMode::kPlus; + paint.color = Color::Red(); + canvas.DrawCircle(Point(450, 250), 100, paint); + paint.color = Color::Green(); + canvas.DrawCircle(Point(550, 250), 100, paint); + paint.color = Color::Blue(); + canvas.DrawCircle(Point(500, 150), 100, paint); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +// Bug: https://github.com/flutter/flutter/issues/142549 +TEST_P(AiksTest, BlendModePlusAlphaWideGamut) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("This backend doesn't yet support wide gamut."); + } + EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), + PixelFormat::kR16G16B16A16Float); + auto texture = CreateTextureForFixture("airplane.jpg", + /*enable_mipmapping=*/true); + + Canvas canvas; + canvas.Scale(GetContentScale()); + canvas.DrawPaint({.color = Color(0.9, 1.0, 0.9, 1.0)}); + canvas.SaveLayer({}); + Paint paint; + paint.blend_mode = BlendMode::kPlus; + paint.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); + paint.color = Color::White(); + canvas.DrawImageRect( + std::make_shared(texture), Rect::MakeSize(texture->GetSize()), + Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); + canvas.Restore(); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +// Bug: https://github.com/flutter/flutter/issues/142549 +TEST_P(AiksTest, BlendModePlusAlphaColorFilterWideGamut) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("This backend doesn't yet support wide gamut."); + } + EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), + PixelFormat::kR16G16B16A16Float); + auto texture = CreateTextureForFixture("airplane.jpg", + /*enable_mipmapping=*/true); + + Canvas canvas; + canvas.Scale(GetContentScale()); + canvas.DrawPaint({.color = Color(0.1, 0.2, 0.1, 1.0)}); + canvas.SaveLayer({ + .color_filter = + ColorFilter::MakeBlend(BlendMode::kPlus, Color(Vector4{1, 0, 0, 1})), + }); + Paint paint; + paint.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); + paint.color = Color::White(); + canvas.DrawImageRect( + std::make_shared(texture), Rect::MakeSize(texture->GetSize()), + Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); + canvas.Restore(); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +#define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode}, + +struct BlendModeSelection { + std::vector blend_mode_names; + std::vector blend_mode_values; +}; + +static BlendModeSelection GetBlendModeSelection() { + std::vector blend_mode_names; + std::vector blend_mode_values; + { + const std::vector> blends = { + IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TUPLE)}; + assert(blends.size() == + static_cast(Entity::kLastAdvancedBlendMode) + 1); + for (const auto& [name, mode] : blends) { + blend_mode_names.push_back(name); + blend_mode_values.push_back(mode); + } + } + + return {blend_mode_names, blend_mode_values}; +} + +TEST_P(AiksTest, ColorWheel) { + // Compare with https://fiddle.skia.org/c/@BlendModes + + BlendModeSelection blend_modes = GetBlendModeSelection(); + + auto draw_color_wheel = [](Canvas& canvas) { + /// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 -> + /// cyan domain: r >= 0 (because modulo used is non euclidean) + auto color_wheel_sampler = [](Radians r) { + Scalar x = r.radians / k2Pi + 1; + + // https://www.desmos.com/calculator/6nhjelyoaj + auto color_cycle = [](Scalar x) { + Scalar cycle = std::fmod(x, 6.0f); + return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle))); + }; + return Color(color_cycle(6 * x + 1), // + color_cycle(6 * x - 1), // + color_cycle(6 * x - 3), // + 1); + }; + + Paint paint; + paint.blend_mode = BlendMode::kSourceOver; + + // Draw a fancy color wheel for the backdrop. + // https://www.desmos.com/calculator/xw7kafthwd + const int max_dist = 900; + for (int i = 0; i <= 900; i++) { + Radians r(kPhi / k2Pi * i); + Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians); + Scalar normalized_distance = static_cast(i) / max_dist; + + paint.color = + color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance); + Point position(distance * std::sin(r.radians), + -distance * std::cos(r.radians)); + + canvas.DrawCircle(position, 9 + normalized_distance * 3, paint); + } + }; + + std::shared_ptr color_wheel_image; + Matrix color_wheel_transform; + + auto callback = [&](AiksContext& renderer) -> std::optional { + // UI state. + static bool cache_the_wheel = true; + static int current_blend_index = 3; + static float dst_alpha = 1; + static float src_alpha = 1; + static Color color0 = Color::Red(); + static Color color1 = Color::Green(); + static Color color2 = Color::Blue(); + + if (AiksTest::ImGuiBegin("Controls", nullptr, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Checkbox("Cache the wheel", &cache_the_wheel); + ImGui::ListBox("Blending mode", ¤t_blend_index, + blend_modes.blend_mode_names.data(), + blend_modes.blend_mode_names.size()); + ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1); + ImGui::ColorEdit4("Color A", reinterpret_cast(&color0)); + ImGui::ColorEdit4("Color B", reinterpret_cast(&color1)); + ImGui::ColorEdit4("Color C", reinterpret_cast(&color2)); + ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1); + ImGui::End(); + } + + static Point content_scale; + Point new_content_scale = GetContentScale(); + + if (!cache_the_wheel || new_content_scale != content_scale) { + content_scale = new_content_scale; + + // Render the color wheel to an image. + + Canvas canvas; + canvas.Scale(content_scale); + + canvas.Translate(Vector2(500, 400)); + canvas.Scale(Vector2(3, 3)); + + draw_color_wheel(canvas); + auto color_wheel_picture = canvas.EndRecordingAsPicture(); + auto snapshot = color_wheel_picture.Snapshot(renderer); + if (!snapshot.has_value() || !snapshot->texture) { + return std::nullopt; + } + color_wheel_image = std::make_shared(snapshot->texture); + color_wheel_transform = snapshot->transform; + } + + Canvas canvas; + + // Blit the color wheel backdrop to the screen with managed alpha. + canvas.SaveLayer({.color = Color::White().WithAlpha(dst_alpha), + .blend_mode = BlendMode::kSource}); + { + canvas.DrawPaint({.color = Color::White()}); + + canvas.Save(); + canvas.Transform(color_wheel_transform); + canvas.DrawImage(color_wheel_image, Point(), Paint()); + canvas.Restore(); + } + canvas.Restore(); + + canvas.Scale(content_scale); + canvas.Translate(Vector2(500, 400)); + canvas.Scale(Vector2(3, 3)); + + // Draw 3 circles to a subpass and blend it in. + canvas.SaveLayer( + {.color = Color::White().WithAlpha(src_alpha), + .blend_mode = blend_modes.blend_mode_values[current_blend_index]}); + { + Paint paint; + paint.blend_mode = BlendMode::kPlus; + const Scalar x = std::sin(k2Pi / 3); + const Scalar y = -std::cos(k2Pi / 3); + paint.color = color0; + canvas.DrawCircle(Point(-x, y) * 45, 65, paint); + paint.color = color1; + canvas.DrawCircle(Point(0, -1) * 45, 65, paint); + paint.color = color2; + canvas.DrawCircle(Point(x, y) * 45, 65, paint); + } + canvas.Restore(); + + return canvas.EndRecordingAsPicture(); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +TEST_P(AiksTest, ForegroundBlendSubpassCollapseOptimization) { + Canvas canvas; + + canvas.SaveLayer({ + .color_filter = + ColorFilter::MakeBlend(BlendMode::kColorDodge, Color::Red()), + }); + + canvas.Translate({500, 300, 0}); + canvas.Rotate(Radians(2 * kPi / 3)); + canvas.DrawRect(Rect::MakeXYWH(100, 100, 200, 200), {.color = Color::Blue()}); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, ClearBlend) { + Canvas canvas; + Paint white; + white.color = Color::Blue(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white); + + Paint clear; + clear.blend_mode = BlendMode::kClear; + + canvas.DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear); +} + +static Picture BlendModeTest(Vector2 content_scale, + BlendMode blend_mode, + const std::shared_ptr& src_image, + const std::shared_ptr& dst_image) { + Color destination_color = Color::CornflowerBlue().WithAlpha(0.75); + auto source_colors = std::vector({Color::White().WithAlpha(0.75), + Color::LimeGreen().WithAlpha(0.75), + Color::Black().WithAlpha(0.75)}); + + Canvas canvas; + canvas.DrawPaint({.color = Color::Black()}); + // TODO(bdero): Why does this cause the left image to double scale on high DPI + // displays. + // canvas.Scale(content_scale); + + //---------------------------------------------------------------------------- + /// 1. Save layer blending (top squares). + /// + + canvas.Save(); + for (const auto& color : source_colors) { + canvas.Save(); + { + canvas.ClipRect(Rect::MakeXYWH(25, 25, 100, 100)); + // Perform the blend in a SaveLayer so that the initial backdrop color is + // fully transparent black. SourceOver blend the result onto the parent + // pass. + canvas.SaveLayer({}); + { + canvas.DrawPaint({.color = destination_color}); + // Draw the source color in an offscreen pass and blend it to the parent + // pass. + canvas.SaveLayer({.blend_mode = blend_mode}); + { // + canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100), {.color = color}); + } + canvas.Restore(); + } + canvas.Restore(); + } + canvas.Restore(); + canvas.Translate(Vector2(100, 0)); + } + canvas.RestoreToCount(0); + + //---------------------------------------------------------------------------- + /// 2. CPU blend modes (bottom squares). + /// + + canvas.Save(); + canvas.Translate({0, 100}); + // Perform the blend in a SaveLayer so that the initial backdrop color is + // fully transparent black. SourceOver blend the result onto the parent pass. + canvas.SaveLayer({}); + for (const auto& color : source_colors) { + // Simply write the CPU blended color to the pass. + canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100), + {.color = destination_color.Blend(color, blend_mode), + .blend_mode = BlendMode::kSourceOver}); + canvas.Translate(Vector2(100, 0)); + } + canvas.Restore(); + canvas.Restore(); + + //---------------------------------------------------------------------------- + /// 3. Image blending (bottom images). + /// + /// Compare these results with the images in the Flutter blend mode + /// documentation: https://api.flutter.dev/flutter/dart-ui/BlendMode.html + /// + + canvas.Translate({0, 250}); + + // Draw grid behind the images. + canvas.DrawRect(Rect::MakeLTRB(0, 0, 800, 400), + {.color = Color::MakeRGBA8(41, 41, 41, 255)}); + Paint square_paint = {.color = Color::MakeRGBA8(15, 15, 15, 255)}; + for (int y = 0; y < 400 / 8; y++) { + for (int x = 0; x < 800 / 16; x++) { + canvas.DrawRect(Rect::MakeXYWH(x * 16 + (y % 2) * 8, y * 8, 8, 8), + square_paint); + } + } + + // Uploaded image source (left image). + canvas.Save(); + canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver}); + { + canvas.DrawImage(dst_image, {0, 0}, {.blend_mode = BlendMode::kSourceOver}); + canvas.DrawImage(src_image, {0, 0}, {.blend_mode = blend_mode}); + } + canvas.Restore(); + canvas.Restore(); + + // Rendered image source (right image). + canvas.Save(); + canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver}); + { + canvas.DrawImage(dst_image, {400, 0}, + {.blend_mode = BlendMode::kSourceOver}); + canvas.SaveLayer({.blend_mode = blend_mode}); + { + canvas.DrawImage(src_image, {400, 0}, + {.blend_mode = BlendMode::kSourceOver}); + } + canvas.Restore(); + } + canvas.Restore(); + canvas.Restore(); + + return canvas.EndRecordingAsPicture(); +} + +#define BLEND_MODE_TEST(blend_mode) \ + TEST_P(AiksTest, BlendMode##blend_mode) { \ + auto src_image = std::make_shared( \ + CreateTextureForFixture("blend_mode_src.png")); \ + auto dst_image = std::make_shared( \ + CreateTextureForFixture("blend_mode_dst.png")); \ + OpenPlaygroundHere(BlendModeTest( \ + GetContentScale(), BlendMode::k##blend_mode, src_image, dst_image)); \ + } +IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TEST) + +TEST_P(AiksTest, CanDrawPaintMultipleTimesInteractive) { + auto modes = GetBlendModeSelection(); + + auto callback = [&](AiksContext& renderer) -> std::optional { + static Color background = Color::MediumTurquoise(); + static Color foreground = Color::Color::OrangeRed().WithAlpha(0.5); + static int current_blend_index = 3; + + if (AiksTest::ImGuiBegin("Controls", nullptr, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::ColorEdit4("Background", reinterpret_cast(&background)); + ImGui::ColorEdit4("Foreground", reinterpret_cast(&foreground)); + ImGui::ListBox("Blend mode", ¤t_blend_index, + modes.blend_mode_names.data(), + modes.blend_mode_names.size()); + ImGui::End(); + } + + Canvas canvas; + canvas.Scale(Vector2(0.2, 0.2)); + canvas.DrawPaint({.color = background}); + canvas.DrawPaint( + {.color = foreground, + .blend_mode = static_cast(current_blend_index)}); + return canvas.EndRecordingAsPicture(); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index ee375d67628a9..96354f78d14c8 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -130,28 +130,6 @@ TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer) { - Canvas canvas; - - Rect layer_rect = Rect::MakeXYWH(0, 0, 500, 500); - canvas.ClipRect(layer_rect); - - canvas.SaveLayer( - { - .color_filter = ColorFilter::MakeBlend(BlendMode::kDifference, - Color(0, 1, 0, 0.5)), - }, - layer_rect); - - Paint paint; - canvas.DrawPaint({.color = Color::Black()}); - canvas.DrawRect(Rect::MakeXYWH(100, 100, 300, 300), - {.color = Color::White()}); - canvas.Restore(); - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - namespace { bool GenerateMipmap(const std::shared_ptr& context, std::shared_ptr texture, @@ -517,31 +495,6 @@ TEST_P(AiksTest, CanEmptyPictureConvertToImage) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) { - Canvas canvas; - Paint paint; - - paint.color = Color::Red(); - canvas.DrawPaint(paint); - - paint.blend_mode = BlendMode::kSourceOver; - canvas.SaveLayer(paint); - - paint.color = Color::White(); - canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); - - paint.blend_mode = BlendMode::kSource; - canvas.SaveLayer(paint); - - paint.color = Color::Blue(); - canvas.DrawRect(Rect::MakeXYWH(200, 200, 200, 200), paint); - - canvas.Restore(); - canvas.Restore(); - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - TEST_P(AiksTest, CanRenderGroupOpacity) { Canvas canvas; @@ -984,124 +937,6 @@ TEST_P(AiksTest, CanDrawPaintMultipleTimes) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, CanDrawPaintWithAdvancedBlend) { - Canvas canvas; - canvas.Scale(Vector2(0.2, 0.2)); - canvas.DrawPaint({.color = Color::MediumTurquoise()}); - canvas.DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5), - .blend_mode = BlendMode::kHue}); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, DrawPaintWithAdvancedBlendOverFilter) { - Paint filtered = { - .color = Color::Black(), - .mask_blur_descriptor = - Paint::MaskBlurDescriptor{ - .style = FilterContents::BlurStyle::kNormal, - .sigma = Sigma(60), - }, - }; - - Canvas canvas; - canvas.DrawPaint({.color = Color::White()}); - canvas.DrawCircle({300, 300}, 200, filtered); - canvas.DrawPaint({.color = Color::Green(), .blend_mode = BlendMode::kScreen}); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, DrawAdvancedBlendPartlyOffscreen) { - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 1.0}; - - Paint paint = { - .color_source = ColorSource::MakeLinearGradient( - {0, 0}, {100, 100}, std::move(colors), std::move(stops), - Entity::TileMode::kRepeat, Matrix::MakeScale(Vector3(0.3, 0.3, 0.3))), - .blend_mode = BlendMode::kLighten, - }; - - Canvas canvas; - canvas.DrawPaint({.color = Color::Blue()}); - canvas.Scale(Vector2(2, 2)); - canvas.ClipRect(Rect::MakeLTRB(0, 0, 200, 200)); - canvas.DrawCircle({100, 100}, 100, paint); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -#define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode}, - -struct BlendModeSelection { - std::vector blend_mode_names; - std::vector blend_mode_values; -}; - -static BlendModeSelection GetBlendModeSelection() { - std::vector blend_mode_names; - std::vector blend_mode_values; - { - const std::vector> blends = { - IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TUPLE)}; - assert(blends.size() == - static_cast(Entity::kLastAdvancedBlendMode) + 1); - for (const auto& [name, mode] : blends) { - blend_mode_names.push_back(name); - blend_mode_values.push_back(mode); - } - } - - return {blend_mode_names, blend_mode_values}; -} - -TEST_P(AiksTest, CanDrawPaintMultipleTimesInteractive) { - auto modes = GetBlendModeSelection(); - - auto callback = [&](AiksContext& renderer) -> std::optional { - static Color background = Color::MediumTurquoise(); - static Color foreground = Color::Color::OrangeRed().WithAlpha(0.5); - static int current_blend_index = 3; - - if (AiksTest::ImGuiBegin("Controls", nullptr, - ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::ColorEdit4("Background", reinterpret_cast(&background)); - ImGui::ColorEdit4("Foreground", reinterpret_cast(&foreground)); - ImGui::ListBox("Blend mode", ¤t_blend_index, - modes.blend_mode_names.data(), - modes.blend_mode_names.size()); - ImGui::End(); - } - - Canvas canvas; - canvas.Scale(Vector2(0.2, 0.2)); - canvas.DrawPaint({.color = background}); - canvas.DrawPaint( - {.color = foreground, - .blend_mode = static_cast(current_blend_index)}); - return canvas.EndRecordingAsPicture(); - }; - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - -TEST_P(AiksTest, PaintBlendModeIsRespected) { - Paint paint; - Canvas canvas; - // Default is kSourceOver. - paint.color = Color(1, 0, 0, 0.5); - canvas.DrawCircle(Point(150, 200), 100, paint); - paint.color = Color(0, 1, 0, 0.5); - canvas.DrawCircle(Point(250, 200), 100, paint); - - paint.blend_mode = BlendMode::kPlus; - paint.color = Color::Red(); - canvas.DrawCircle(Point(450, 250), 100, paint); - paint.color = Color::Green(); - canvas.DrawCircle(Point(550, 250), 100, paint); - paint.color = Color::Blue(); - canvas.DrawCircle(Point(500, 150), 100, paint); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - // This makes sure the WideGamut named tests use 16bit float pixel format. TEST_P(AiksTest, F16WideGamut) { if (GetParam() != PlaygroundBackend::kMetal) { @@ -1118,196 +953,6 @@ TEST_P(AiksTest, NotF16) { GetContext()->GetCapabilities()->GetDefaultColorFormat())); } -// Bug: https://github.com/flutter/flutter/issues/142549 -TEST_P(AiksTest, BlendModePlusAlphaWideGamut) { - if (GetParam() != PlaygroundBackend::kMetal) { - GTEST_SKIP_("This backend doesn't yet support wide gamut."); - } - EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), - PixelFormat::kR16G16B16A16Float); - auto texture = CreateTextureForFixture("airplane.jpg", - /*enable_mipmapping=*/true); - - Canvas canvas; - canvas.Scale(GetContentScale()); - canvas.DrawPaint({.color = Color(0.9, 1.0, 0.9, 1.0)}); - canvas.SaveLayer({}); - Paint paint; - paint.blend_mode = BlendMode::kPlus; - paint.color = Color::Red(); - canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); - paint.color = Color::White(); - canvas.DrawImageRect( - std::make_shared(texture), Rect::MakeSize(texture->GetSize()), - Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); - canvas.Restore(); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -// Bug: https://github.com/flutter/flutter/issues/142549 -TEST_P(AiksTest, BlendModePlusAlphaColorFilterWideGamut) { - if (GetParam() != PlaygroundBackend::kMetal) { - GTEST_SKIP_("This backend doesn't yet support wide gamut."); - } - EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(), - PixelFormat::kR16G16B16A16Float); - auto texture = CreateTextureForFixture("airplane.jpg", - /*enable_mipmapping=*/true); - - Canvas canvas; - canvas.Scale(GetContentScale()); - canvas.DrawPaint({.color = Color(0.1, 0.2, 0.1, 1.0)}); - canvas.SaveLayer({ - .color_filter = - ColorFilter::MakeBlend(BlendMode::kPlus, Color(Vector4{1, 0, 0, 1})), - }); - Paint paint; - paint.color = Color::Red(); - canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint); - paint.color = Color::White(); - canvas.DrawImageRect( - std::make_shared(texture), Rect::MakeSize(texture->GetSize()), - Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint); - canvas.Restore(); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, ColorWheel) { - // Compare with https://fiddle.skia.org/c/@BlendModes - - BlendModeSelection blend_modes = GetBlendModeSelection(); - - auto draw_color_wheel = [](Canvas& canvas) { - /// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 -> - /// cyan domain: r >= 0 (because modulo used is non euclidean) - auto color_wheel_sampler = [](Radians r) { - Scalar x = r.radians / k2Pi + 1; - - // https://www.desmos.com/calculator/6nhjelyoaj - auto color_cycle = [](Scalar x) { - Scalar cycle = std::fmod(x, 6.0f); - return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle))); - }; - return Color(color_cycle(6 * x + 1), // - color_cycle(6 * x - 1), // - color_cycle(6 * x - 3), // - 1); - }; - - Paint paint; - paint.blend_mode = BlendMode::kSourceOver; - - // Draw a fancy color wheel for the backdrop. - // https://www.desmos.com/calculator/xw7kafthwd - const int max_dist = 900; - for (int i = 0; i <= 900; i++) { - Radians r(kPhi / k2Pi * i); - Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians); - Scalar normalized_distance = static_cast(i) / max_dist; - - paint.color = - color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance); - Point position(distance * std::sin(r.radians), - -distance * std::cos(r.radians)); - - canvas.DrawCircle(position, 9 + normalized_distance * 3, paint); - } - }; - - std::shared_ptr color_wheel_image; - Matrix color_wheel_transform; - - auto callback = [&](AiksContext& renderer) -> std::optional { - // UI state. - static bool cache_the_wheel = true; - static int current_blend_index = 3; - static float dst_alpha = 1; - static float src_alpha = 1; - static Color color0 = Color::Red(); - static Color color1 = Color::Green(); - static Color color2 = Color::Blue(); - - if (AiksTest::ImGuiBegin("Controls", nullptr, - ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Checkbox("Cache the wheel", &cache_the_wheel); - ImGui::ListBox("Blending mode", ¤t_blend_index, - blend_modes.blend_mode_names.data(), - blend_modes.blend_mode_names.size()); - ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1); - ImGui::ColorEdit4("Color A", reinterpret_cast(&color0)); - ImGui::ColorEdit4("Color B", reinterpret_cast(&color1)); - ImGui::ColorEdit4("Color C", reinterpret_cast(&color2)); - ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1); - ImGui::End(); - } - - static Point content_scale; - Point new_content_scale = GetContentScale(); - - if (!cache_the_wheel || new_content_scale != content_scale) { - content_scale = new_content_scale; - - // Render the color wheel to an image. - - Canvas canvas; - canvas.Scale(content_scale); - - canvas.Translate(Vector2(500, 400)); - canvas.Scale(Vector2(3, 3)); - - draw_color_wheel(canvas); - auto color_wheel_picture = canvas.EndRecordingAsPicture(); - auto snapshot = color_wheel_picture.Snapshot(renderer); - if (!snapshot.has_value() || !snapshot->texture) { - return std::nullopt; - } - color_wheel_image = std::make_shared(snapshot->texture); - color_wheel_transform = snapshot->transform; - } - - Canvas canvas; - - // Blit the color wheel backdrop to the screen with managed alpha. - canvas.SaveLayer({.color = Color::White().WithAlpha(dst_alpha), - .blend_mode = BlendMode::kSource}); - { - canvas.DrawPaint({.color = Color::White()}); - - canvas.Save(); - canvas.Transform(color_wheel_transform); - canvas.DrawImage(color_wheel_image, Point(), Paint()); - canvas.Restore(); - } - canvas.Restore(); - - canvas.Scale(content_scale); - canvas.Translate(Vector2(500, 400)); - canvas.Scale(Vector2(3, 3)); - - // Draw 3 circles to a subpass and blend it in. - canvas.SaveLayer( - {.color = Color::White().WithAlpha(src_alpha), - .blend_mode = blend_modes.blend_mode_values[current_blend_index]}); - { - Paint paint; - paint.blend_mode = BlendMode::kPlus; - const Scalar x = std::sin(k2Pi / 3); - const Scalar y = -std::cos(k2Pi / 3); - paint.color = color0; - canvas.DrawCircle(Point(-x, y) * 45, 65, paint); - paint.color = color1; - canvas.DrawCircle(Point(0, -1) * 45, 65, paint); - paint.color = color2; - canvas.DrawCircle(Point(x, y) * 45, 65, paint); - } - canvas.Restore(); - - return canvas.EndRecordingAsPicture(); - }; - - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - TEST_P(AiksTest, TransformMultipliesCorrectly) { Canvas canvas; ASSERT_MATRIX_NEAR(canvas.GetCurrentTransform(), Matrix()); @@ -2236,21 +1881,6 @@ TEST_P(AiksTest, CollapsedDrawPaintInSubpassBackdropFilter) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, ForegroundBlendSubpassCollapseOptimization) { - Canvas canvas; - - canvas.SaveLayer({ - .color_filter = - ColorFilter::MakeBlend(BlendMode::kColorDodge, Color::Red()), - }); - - canvas.Translate({500, 300, 0}); - canvas.Rotate(Radians(2 * kPi / 3)); - canvas.DrawRect(Rect::MakeXYWH(100, 100, 200, 200), {.color = Color::Blue()}); - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - TEST_P(AiksTest, ColorMatrixFilterSubpassCollapseOptimization) { Canvas canvas; @@ -2300,130 +1930,6 @@ TEST_P(AiksTest, SrgbToLinearFilterSubpassCollapseOptimization) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -static Picture BlendModeTest(Vector2 content_scale, - BlendMode blend_mode, - const std::shared_ptr& src_image, - const std::shared_ptr& dst_image) { - Color destination_color = Color::CornflowerBlue().WithAlpha(0.75); - auto source_colors = std::vector({Color::White().WithAlpha(0.75), - Color::LimeGreen().WithAlpha(0.75), - Color::Black().WithAlpha(0.75)}); - - Canvas canvas; - canvas.DrawPaint({.color = Color::Black()}); - // TODO(bdero): Why does this cause the left image to double scale on high DPI - // displays. - // canvas.Scale(content_scale); - - //---------------------------------------------------------------------------- - /// 1. Save layer blending (top squares). - /// - - canvas.Save(); - for (const auto& color : source_colors) { - canvas.Save(); - { - canvas.ClipRect(Rect::MakeXYWH(25, 25, 100, 100)); - // Perform the blend in a SaveLayer so that the initial backdrop color is - // fully transparent black. SourceOver blend the result onto the parent - // pass. - canvas.SaveLayer({}); - { - canvas.DrawPaint({.color = destination_color}); - // Draw the source color in an offscreen pass and blend it to the parent - // pass. - canvas.SaveLayer({.blend_mode = blend_mode}); - { // - canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100), {.color = color}); - } - canvas.Restore(); - } - canvas.Restore(); - } - canvas.Restore(); - canvas.Translate(Vector2(100, 0)); - } - canvas.RestoreToCount(0); - - //---------------------------------------------------------------------------- - /// 2. CPU blend modes (bottom squares). - /// - - canvas.Save(); - canvas.Translate({0, 100}); - // Perform the blend in a SaveLayer so that the initial backdrop color is - // fully transparent black. SourceOver blend the result onto the parent pass. - canvas.SaveLayer({}); - for (const auto& color : source_colors) { - // Simply write the CPU blended color to the pass. - canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100), - {.color = destination_color.Blend(color, blend_mode), - .blend_mode = BlendMode::kSourceOver}); - canvas.Translate(Vector2(100, 0)); - } - canvas.Restore(); - canvas.Restore(); - - //---------------------------------------------------------------------------- - /// 3. Image blending (bottom images). - /// - /// Compare these results with the images in the Flutter blend mode - /// documentation: https://api.flutter.dev/flutter/dart-ui/BlendMode.html - /// - - canvas.Translate({0, 250}); - - // Draw grid behind the images. - canvas.DrawRect(Rect::MakeLTRB(0, 0, 800, 400), - {.color = Color::MakeRGBA8(41, 41, 41, 255)}); - Paint square_paint = {.color = Color::MakeRGBA8(15, 15, 15, 255)}; - for (int y = 0; y < 400 / 8; y++) { - for (int x = 0; x < 800 / 16; x++) { - canvas.DrawRect(Rect::MakeXYWH(x * 16 + (y % 2) * 8, y * 8, 8, 8), - square_paint); - } - } - - // Uploaded image source (left image). - canvas.Save(); - canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver}); - { - canvas.DrawImage(dst_image, {0, 0}, {.blend_mode = BlendMode::kSourceOver}); - canvas.DrawImage(src_image, {0, 0}, {.blend_mode = blend_mode}); - } - canvas.Restore(); - canvas.Restore(); - - // Rendered image source (right image). - canvas.Save(); - canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver}); - { - canvas.DrawImage(dst_image, {400, 0}, - {.blend_mode = BlendMode::kSourceOver}); - canvas.SaveLayer({.blend_mode = blend_mode}); - { - canvas.DrawImage(src_image, {400, 0}, - {.blend_mode = BlendMode::kSourceOver}); - } - canvas.Restore(); - } - canvas.Restore(); - canvas.Restore(); - - return canvas.EndRecordingAsPicture(); -} - -#define BLEND_MODE_TEST(blend_mode) \ - TEST_P(AiksTest, BlendMode##blend_mode) { \ - auto src_image = std::make_shared( \ - CreateTextureForFixture("blend_mode_src.png")); \ - auto dst_image = std::make_shared( \ - CreateTextureForFixture("blend_mode_dst.png")); \ - OpenPlaygroundHere(BlendModeTest( \ - GetContentScale(), BlendMode::k##blend_mode, src_image, dst_image)); \ - } -IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TEST) - TEST_P(AiksTest, TranslucentSaveLayerDrawsCorrectly) { Canvas canvas; @@ -3227,18 +2733,6 @@ TEST_P(AiksTest, VerticesGeometryUVPositionDataWithTranslate) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, ClearBlend) { - Canvas canvas; - Paint white; - white.color = Color::Blue(); - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white); - - Paint clear; - clear.blend_mode = BlendMode::kClear; - - canvas.DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear); -} - TEST_P(AiksTest, MatrixImageFilterMagnify) { Canvas canvas; canvas.Scale(GetContentScale()); @@ -3587,6 +3081,7 @@ TEST_P(AiksTest, MipmapGenerationWorksCorrectly) { // â–ˆ the subdivisions of AiksTest to avoid having one massive file. // â–ˆ // â–ˆ Subdivisions: +// â–ˆ - aiks_blend_unittests.cc // â–ˆ - aiks_blur_unittests.cc // â–ˆ - aiks_gradient_unittests.cc // â–ˆ - aiks_path_unittests.cc From 4c079a6ff5022ae5d06cb0f44a8092b77adf5aea Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 13:10:09 -0700 Subject: [PATCH 27/49] Remove the tests for `rotate` and `crop` from the Android `scenario_app`. (#51769) Closes https://github.com/flutter/flutter/issues/145957. As @jonahwilliams and @johnmccutchan and I discussed (https://github.com/flutter/flutter/issues/144407), the functionality that was being tested was actually _Android's_ ability to rotate and crop `SurfaceTexture`-backed textures. This same functionality doesn't even exist in the `ImageReader`-based textures (read: modern Android devices): > Due to an oversight by Android, ImageReader backed surfaces do not respect metadata applied to the surface (rotation & crop). Rotation information is not available at all and crop information is corrupted by the ImageReader (only the width/height is propagated the origin offset is not). We might decide to re-add this functionality in the Dart `Texture` widget, but given we'll be migrating our plugins to `SurfaceProducer` (again, read: using `ImageTexture` for most Android phones), it's pointless to test this (and isn't even testing Flutter's code). This reduces our test suite significantly (8 tests down to 2), which should also help with runtime and flakiness. /cc @zanderso who I'm sure will be stoked. --- testing/scenario_app/android/README.md | 26 +++++++ testing/scenario_app/android/app/build.gradle | 1 + .../scenario_app/android/app/gradle.lockfile | 29 +++++--- .../scenariosui/ExternalTextureTests.java | 73 +------------------ .../ExternalTextureFlutterActivity.java | 24 ++---- .../android/expected_golden_output.txt | 8 +- 6 files changed, 56 insertions(+), 105 deletions(-) diff --git a/testing/scenario_app/android/README.md b/testing/scenario_app/android/README.md index c3d5e0cb7fc46..d4e4627eec5f2 100644 --- a/testing/scenario_app/android/README.md +++ b/testing/scenario_app/android/README.md @@ -355,6 +355,32 @@ device (you might find it easier trying the `stdout` of the test first, which uses rudimentary log filtering). In the case of multiple runs, the logs are prefixed with the test configuration and run attempt. +### Gradle is failing due to an "not part of the dependency lock state" error + +If you update dependencies in the `app/build.gradle` file, you may encounter an +error (probably in CI) that looks like: + +```txt +FAILED: scenario_app/reports/lint-results.xml +vpython3 ../../flutter/testing/rules/run_gradle.py /b/s/w/ir/cache/builder/src/flutter/testing/scenario_app/android lint --no-daemon -Pflutter_jar=/b/s/w/ir/cache/builder/src/out/android_emulator_skia_debug_x64/flutter.jar -Pout_dir=/b/s/w/ir/cache/builder/src/out/android_emulator_skia_debug_x64/scenario_app --project-cache-dir=/b/s/w/ir/cache/builder/src/out/android_emulator_skia_debug_x64/scenario_app/.gradle --gradle-user-home=/b/s/w/ir/cache/builder/src/out/android_emulator_skia_debug_x64/scenario_app/.gradle + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':app:checkDebugAarMetadata'. +> Could not resolve all files for configuration ':app:debugRuntimeClasspath'. + > Resolved 'org.hamcrest:hamcrest-core:1.3' which is not part of the dependency lock state + > Resolved 'com.google.code.findbugs:jsr305:2.0.2' which is not part of the dependency lock state +``` + +This is because [`gradle.lockfile`](./app/gradle.lockfile) is out of date. To +update it, run: + +```sh +cd testing/scenario_app/android +$ENGINE_SRC/third_party/gradle/bin/gradle app:dependencies --write-locks +``` + ## Getting Help To suggest changes, or highlight problems, please [file an issue](https://github.com/flutter/flutter/issues/new?labels=e:%20scenario-app,engine,platform-android,fyi-android,team-engine). diff --git a/testing/scenario_app/android/app/build.gradle b/testing/scenario_app/android/app/build.gradle index c65cc89148e8f..821915b3e56c7 100644 --- a/testing/scenario_app/android/app/build.gradle +++ b/testing/scenario_app/android/app/build.gradle @@ -59,6 +59,7 @@ dependencies { } implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' diff --git a/testing/scenario_app/android/app/gradle.lockfile b/testing/scenario_app/android/app/gradle.lockfile index e083af965d3fb..fedf60cf04806 100644 --- a/testing/scenario_app/android/app/gradle.lockfile +++ b/testing/scenario_app/android/app/gradle.lockfile @@ -2,7 +2,7 @@ # Manual edits can break the build and are not advised. # This file is expected to be part of source control. androidx.activity:activity:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.annotation:annotation:1.0.0=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata androidx.annotation:annotation:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.appcompat:appcompat:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -11,6 +11,7 @@ androidx.arch.core:core-runtime:2.0.0=debugAndroidTestCompileClasspath,debugComp androidx.asynclayoutinflater:asynclayoutinflater:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.cardview:cardview:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.collection:collection:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.concurrent:concurrent-futures:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.constraintlayout:constraintlayout-solver:1.1.3=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.constraintlayout:constraintlayout:1.1.3=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.coordinatorlayout:coordinatorlayout:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -24,7 +25,7 @@ androidx.interpolator:interpolator:1.0.0=debugAndroidTestCompileClasspath,debugC androidx.legacy:legacy-support-core-ui:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.legacy:legacy-support-core-utils:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-common-java8:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-common:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.lifecycle:lifecycle-common:2.3.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata-core:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -38,10 +39,15 @@ androidx.slidingpanelayout:slidingpanelayout:1.0.0=debugAndroidTestCompileClassp androidx.swiperefreshlayout:swiperefreshlayout:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.test.espresso:espresso-core:3.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath androidx.test.espresso:espresso-idling-resource:3.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath -androidx.test:monitor:1.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath +androidx.test.ext:junit:1.1.5=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test.services:storage:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:annotation:1.0.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:core:1.5.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:monitor:1.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata +androidx.test:monitor:1.6.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.test:rules:1.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath androidx.test:runner:1.2.0=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath -androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.transition:transition:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.vectordrawable:vectordrawable-animated:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.vectordrawable:vectordrawable:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -80,12 +86,14 @@ com.android:zipflinger:7.0.0=lintClassPath com.beust:jcommander:1.78=lintClassPath com.github.javaparser:javaparser-core:3.17.0=lintClassPath com.google.android.material:material:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.findbugs:jsr305:3.0.2=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath +com.google.code.findbugs:jsr305:2.0.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.code.findbugs:jsr305:3.0.2=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata,lintClassPath com.google.code.gson:gson:2.8.6=lintClassPath com.google.errorprone:error_prone_annotations:2.3.4=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath com.google.guava:failureaccess:1.0.1=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath com.google.guava:guava:30.1-android=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath com.google.guava:guava:30.1-jre=lintClassPath +com.google.guava:listenablefuture:1.0=debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath com.google.j2objc:j2objc-annotations:1.3=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath com.google.jimfs:jimfs:1.1=lintClassPath @@ -122,8 +130,9 @@ jakarta.activation:jakarta.activation-api:1.2.1=lintClassPath jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=lintClassPath javax.inject:javax.inject:1=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath jline:jline:2.14.6=lintClassPath -junit:junit:4.12=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath +junit:junit:4.12=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata junit:junit:4.13.1=lintClassPath +junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.java.dev.jna:jna-platform:5.6.0=lintClassPath net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,lintClassPath net.sf.jopt-simple:jopt-simple:4.9=lintClassPath @@ -165,7 +174,7 @@ org.codehaus.groovy:groovy-xml:3.0.7=lintClassPath org.codehaus.groovy:groovy:3.0.7=lintClassPath org.glassfish.jaxb:jaxb-runtime:2.3.2=lintClassPath org.glassfish.jaxb:txw2:2.3.2=lintClassPath -org.hamcrest:hamcrest-core:1.3=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,lintClassPath +org.hamcrest:hamcrest-core:1.3=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,lintClassPath,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-integration:1.3=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath org.hamcrest:hamcrest-library:1.3=androidTestImplementationDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestRuntimeClasspath org.jacoco:org.jacoco.agent:0.8.8=androidJacocoAnt @@ -181,14 +190,16 @@ org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinCompilerClasspath,kotlinKlibCom org.jetbrains.kotlin:kotlin-script-runtime:1.6.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-stdlib-common:1.4.21=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata org.jetbrains.kotlin:kotlin-stdlib-common:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.6.10=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.6.10=apiDependenciesMetadata,debugApiDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,releaseApiDependenciesMetadata +org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.4.21=androidTestImplementationDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata org.jetbrains.kotlin:kotlin-stdlib:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.6.10=apiDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.6.10=apiDependenciesMetadata,debugApiDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,releaseApiDependenciesMetadata +org.jetbrains.kotlin:kotlin-stdlib:1.7.10=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java index dd02b4956edcb..38383810ae96c 100644 --- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java +++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java @@ -4,15 +4,11 @@ package dev.flutter.scenariosui; -import static io.flutter.Build.API_LEVELS; - import android.content.Intent; -import android.graphics.Rect; import androidx.annotation.NonNull; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; -import androidx.test.filters.SdkSuppress; import androidx.test.rule.ActivityTestRule; -import androidx.test.runner.AndroidJUnit4; import dev.flutter.scenarios.ExternalTextureFlutterActivity; import org.junit.Before; import org.junit.Rule; @@ -22,10 +18,7 @@ @RunWith(AndroidJUnit4.class) @LargeTest public class ExternalTextureTests { - private static final int SURFACE_WIDTH = 192; - private static final int SURFACE_HEIGHT = 256; - - Intent intent; + private Intent intent; @Rule @NonNull public ActivityTestRule activityRule = @@ -54,66 +47,4 @@ public void testMediaSurface() throws Exception { ScreenshotUtil.capture( activityRule.launchActivity(intent), "ExternalTextureTests_testMediaSurface"); } - - @Test - public void testRotatedMediaSurface_90() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "media"); - intent.putExtra("rotation", 90); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), "ExternalTextureTests_testRotatedMediaSurface_90"); - } - - @Test - public void testRotatedMediaSurface_180() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "media"); - intent.putExtra("rotation", 180); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), "ExternalTextureTests_testRotatedMediaSurface_180"); - } - - @Test - public void testRotatedMediaSurface_270() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "media"); - intent.putExtra("rotation", 270); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), "ExternalTextureTests_testRotatedMediaSurface_270"); - } - - @Test - @SdkSuppress(minSdkVersion = API_LEVELS.API_23) - public void testCroppedMediaSurface_bottomLeft() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "image"); - intent.putExtra("crop", new Rect(0, 0, SURFACE_WIDTH / 2, SURFACE_HEIGHT / 2)); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), - "ExternalTextureTests_testCroppedMediaSurface_bottomLeft"); - } - - @Test - @SdkSuppress(minSdkVersion = API_LEVELS.API_23) - public void testCroppedMediaSurface_topRight() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "image"); - intent.putExtra( - "crop", new Rect(SURFACE_WIDTH / 2, SURFACE_HEIGHT / 2, SURFACE_WIDTH, SURFACE_HEIGHT)); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), - "ExternalTextureTests_testCroppedMediaSurface_topRight"); - } - - @Test - @SdkSuppress(minSdkVersion = API_LEVELS.API_23) - public void testCroppedRotatedMediaSurface_bottomLeft_90() throws Exception { - intent.putExtra("scenario_name", "display_texture"); - intent.putExtra("surface_renderer", "image"); - intent.putExtra("crop", new Rect(0, 0, SURFACE_WIDTH / 2, SURFACE_HEIGHT / 2)); - intent.putExtra("rotation", 90); - ScreenshotUtil.capture( - activityRule.launchActivity(intent), - "ExternalTextureTests_testCroppedRotatedMediaSurface_bottomLeft_90"); - } } diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java index 9b42bff82a3d6..753f2e2690fb8 100644 --- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java +++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java @@ -11,7 +11,6 @@ import android.graphics.ImageFormat; import android.graphics.LinearGradient; import android.graphics.Paint; -import android.graphics.Rect; import android.graphics.Shader.TileMode; import android.hardware.HardwareBuffer; import android.media.Image; @@ -62,7 +61,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { String surfaceRenderer = getIntent().getStringExtra("surface_renderer"); assert surfaceRenderer != null; - flutterRenderer = selectSurfaceRenderer(surfaceRenderer, getIntent().getExtras()); + flutterRenderer = selectSurfaceRenderer(surfaceRenderer); // Create and place a SurfaceView above the Flutter content. SurfaceView surfaceView = new SurfaceView(getContext()); @@ -98,19 +97,18 @@ public void waitUntilFlutterRendered() { } } - private SurfaceRenderer selectSurfaceRenderer(String surfaceRenderer, Bundle extras) { + private SurfaceRenderer selectSurfaceRenderer(String surfaceRenderer) { switch (surfaceRenderer) { case "image": if (VERSION.SDK_INT >= API_LEVELS.API_23) { // CanvasSurfaceRenderer doesn't work correctly when used with ImageSurfaceRenderer. // Use MediaSurfaceRenderer for now. - return new ImageSurfaceRenderer( - selectSurfaceRenderer("media", extras), extras.getParcelable("crop")); + return new ImageSurfaceRenderer(selectSurfaceRenderer("media")); } else { throw new RuntimeException("ImageSurfaceRenderer not supported"); } case "media": - return new MediaSurfaceRenderer(this::createMediaExtractor, extras.getInt("rotation", 0)); + return new MediaSurfaceRenderer(this::createMediaExtractor); case "canvas": default: return new CanvasSurfaceRenderer(); @@ -220,7 +218,6 @@ public void destroy() {} /** Decodes a sample video into the attached Surface. */ private static class MediaSurfaceRenderer implements SurfaceRenderer { private final Supplier extractorSupplier; - private final int rotation; private CountDownLatch onFirstFrame; private Surface surface; @@ -228,9 +225,8 @@ private static class MediaSurfaceRenderer implements SurfaceRenderer { private MediaFormat format; private Thread decodeThread; - protected MediaSurfaceRenderer(Supplier extractorSupplier, int rotation) { + protected MediaSurfaceRenderer(Supplier extractorSupplier) { this.extractorSupplier = extractorSupplier; - this.rotation = rotation; } @Override @@ -241,10 +237,6 @@ public void attach(Surface surface, CountDownLatch onFirstFrame) { extractor = extractorSupplier.get(); format = extractor.getTrackFormat(0); - // NOTE: MediaFormat.KEY_ROTATION was not available until 23+, but the key is still handled on - // API 21+. - format.setInteger("rotation-degrees", rotation); - decodeThread = new Thread(this::decodeThreadMain); decodeThread.start(); } @@ -338,8 +330,6 @@ public void destroy() { @RequiresApi(API_LEVELS.API_23) private static class ImageSurfaceRenderer implements SurfaceRenderer { private final SurfaceRenderer inner; - private final Rect crop; - private CountDownLatch onFirstFrame; private ImageReader reader; private ImageWriter writer; @@ -350,9 +340,8 @@ private static class ImageSurfaceRenderer implements SurfaceRenderer { private boolean canReadImage = true; private boolean canWriteImage = true; - protected ImageSurfaceRenderer(SurfaceRenderer inner, Rect crop) { + protected ImageSurfaceRenderer(SurfaceRenderer inner) { this.inner = inner; - this.crop = crop; } @Override @@ -399,7 +388,6 @@ private void onImageAvailable(ImageReader reader) { canReadImage = false; Image image = reader.acquireLatestImage(); - image.setCropRect(crop); try { canWriteImage = false; writer.queueInputImage(image); diff --git a/testing/scenario_app/android/expected_golden_output.txt b/testing/scenario_app/android/expected_golden_output.txt index da412e233e0ce..2d4b3ad7b451f 100644 --- a/testing/scenario_app/android/expected_golden_output.txt +++ b/testing/scenario_app/android/expected_golden_output.txt @@ -1,12 +1,6 @@ DrawSolidBlueScreenTest.png ExternalTextureTests_testCanvasSurface.png -ExternalTextureTests_testCroppedMediaSurface_bottomLeft.png -ExternalTextureTests_testCroppedMediaSurface_topRight.png -ExternalTextureTests_testCroppedRotatedMediaSurface_bottomLeft_90.png ExternalTextureTests_testMediaSurface.png -ExternalTextureTests_testRotatedMediaSurface_180.png -ExternalTextureTests_testRotatedMediaSurface_270.png -ExternalTextureTests_testRotatedMediaSurface_90.png PlatformTextureUiTests_testPlatformView.png PlatformTextureUiTests_testPlatformViewClippath.png PlatformTextureUiTests_testPlatformViewCliprect.png @@ -60,4 +54,4 @@ PlatformViewWithTextureViewUiTest_testPlatformViewTwoIntersectingOverlays.png PlatformViewWithTextureViewUiTest_testPlatformViewWithoutOverlayIntersection.png SpawnEngineTests_testSpawnedEngine.png logcat.txt -noop.txt \ No newline at end of file +noop.txt From 6d3fb9497a40d1cb8d3725ea427842909417e1e3 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Fri, 29 Mar 2024 13:20:05 -0700 Subject: [PATCH 28/49] Remove _dartobservatory._tcp legacy DNS registration type (#51635) As of https://github.com/flutter/flutter/pull/121606 the flutter tool no longer registers for the legacy `_dartobservatory._tcp` DNS type. Remove the fallback and just register for the preferred `_dartVmService._tcp`. See also https://github.com/dart-lang/sdk/issues/50233 --- .../Source/FlutterDartVMServicePublisher.mm | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartVMServicePublisher.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartVMServicePublisher.mm index b9473566ca890..38288a1f247e2 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartVMServicePublisher.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartVMServicePublisher.mm @@ -65,7 +65,6 @@ @interface DartVMServiceDNSServiceDelegate : NSObject Date: Fri, 29 Mar 2024 13:28:53 -0700 Subject: [PATCH 29/49] Fix the `clangd` builders, and make Linux non-bringup. (#51765) Further work towards https://github.com/flutter/flutter/issues/141641. I could imagine making things `presubmit: false` if we think it's not worth the presubmit capacity. Removed `:copy_dart_sdk` which seems (a) not to work and (b) not needed to use the pre-builts. --- .ci.yaml | 6 ++++-- ci/builders/linux_unopt_debug_no_rbe.json | 13 ++++++++++--- ci/builders/mac_unopt_debug_no_rbe.json | 13 ++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 314883c8dda7f..65e5d9a78a3d2 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -279,7 +279,6 @@ targets: - name: Linux clangd recipe: engine_v2/engine_v2 - bringup: true properties: config_name: linux_unopt_debug_no_rbe @@ -369,8 +368,11 @@ targets: - os=Mac-13 - name: Mac clangd - recipe: engine_v2/engine_v2 bringup: true + recipe: engine_v2/engine_v2 + # Avoid using a Mac orchestrator to save ~5 minutes of Mac host time. + drone_dimensions: + - os=Linux properties: config_name: mac_unopt_debug_no_rbe diff --git a/ci/builders/linux_unopt_debug_no_rbe.json b/ci/builders/linux_unopt_debug_no_rbe.json index 566ece3c5ff63..38ee6cbd60cb8 100644 --- a/ci/builders/linux_unopt_debug_no_rbe.json +++ b/ci/builders/linux_unopt_debug_no_rbe.json @@ -1,7 +1,11 @@ { "_comment": [ "This build is only used to generate compile_commands.json for clangd ", - "and should not be used for any other purpose." + "and should not be used for any other purpose.", + "", + "Note the `flutter/tools/font_subset` target is only used because if no ", + "targets are specified, the build will fail, and if an empty list of ", + "targets are specified, all targets are built (wasteful/slow)" ], "builds": [ { @@ -11,13 +15,16 @@ "debug", "--unoptimized", "--prebuilt-dart-sdk", + "--no-lto", "--no-rbe", - "--no-goma" + "--no-goma", + "--target-dir", + "linux_unopt_debug_no_rbe" ], "name": "linux_unopt_debug_no_rbe", "ninja": { "config": "linux_unopt_debug_no_rbe", - "targets": ["flutter/build/dart:copy_dart_sdk"] + "targets": ["flutter/tools/font_subset"] }, "tests": [ { diff --git a/ci/builders/mac_unopt_debug_no_rbe.json b/ci/builders/mac_unopt_debug_no_rbe.json index 2c8c5eddab5d0..af2acdd1950f1 100644 --- a/ci/builders/mac_unopt_debug_no_rbe.json +++ b/ci/builders/mac_unopt_debug_no_rbe.json @@ -1,7 +1,11 @@ { "_comment": [ "This build is only used to generate compile_commands.json for clangd ", - "and should not be used for any other purpose." + "and should not be used for any other purpose.", + "", + "Note the `flutter/tools/font_subset` target is only used because if no ", + "targets are specified, the build will fail, and if an empty list of ", + "targets are specified, all targets are built (wasteful/slow)" ], "builds": [ { @@ -16,14 +20,17 @@ "debug", "--unoptimized", "--prebuilt-dart-sdk", + "--no-lto", "--no-rbe", "--no-goma", - "--xcode-symlinks" + "--xcode-symlinks", + "--target-dir", + "mac_unopt_debug_no_rbe" ], "name": "mac_unopt_debug_no_rbe", "ninja": { "config": "mac_unopt_debug_no_rbe", - "targets": ["flutter/build/dart:copy_dart_sdk"] + "targets": ["flutter/tools/font_subset"] }, "tests": [ { From 4b6836f8ef00dc23c6f58877e4932416b11b2477 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 14:19:21 -0700 Subject: [PATCH 30/49] Rename `Mac clangd` to `Linux mac_clangd` (#51785) Further work towards https://github.com/flutter/flutter/issues/141641. --- .ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 65e5d9a78a3d2..c770736d3b47e 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -367,7 +367,7 @@ targets: drone_dimensions: - os=Mac-13 - - name: Mac clangd + - name: Linux mac_clangd bringup: true recipe: engine_v2/engine_v2 # Avoid using a Mac orchestrator to save ~5 minutes of Mac host time. From 307e5afe5e9f12825f8761f51222865463b499b5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 17:43:20 -0400 Subject: [PATCH 31/49] Roll Dart SDK from bb65648e20e2 to 52b05146758e (3 revisions) (#51783) https://dart.googlesource.com/sdk.git/+log/bb65648e20e2..52b05146758e 2024-03-29 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-2.0.dev 2024-03-29 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-1.0.dev 2024-03-28 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-0.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC dart-vm-team@google.com,jacksongardner@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 10 +- ci/licenses_golden/licenses_dart | 4 +- sky/packages/sky_engine/LICENSE | 299 ++++++++++++++++++++++++++++++- 3 files changed, 305 insertions(+), 8 deletions(-) diff --git a/DEPS b/DEPS index ea5647ed443d2..e4ef0549face9 100644 --- a/DEPS +++ b/DEPS @@ -62,7 +62,7 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': 'bb65648e20e29abc47acf3dd984518d29fd625c3', + 'dart_revision': '52b05146758e77d548d67835863cd4a1307b30ae', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -72,7 +72,7 @@ vars = { 'dart_browser_launcher_rev': '79562306c86e5c087359a31a60309c8d65a699d3', 'dart_clock_rev': 'daf0fadabc5b3dc8e6e71bf3fb27ef9c3b79df5c', 'dart_collection_rev': 'fc616ff8fd7b732c07b2b19e31b6601e59900ccf', - 'dart_devtools_rev': '7421a2d5d67cbcdec92f1a2ac993b8b64b28d7ca', + 'dart_devtools_rev': '8be1bc8d6862a3fcf8f43917f6e0c783cac06d51', 'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb', 'dart_perfetto_rev': '13ce0c9e13b0940d2476cd0cff2301708a9a2e2b', 'dart_protobuf_gn_rev': 'ca669f79945418f6229e4fef89b666b2a88cbb10', @@ -358,7 +358,7 @@ deps = { Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@9784f012848a7eb321c2037bdb363dfe0eab8bc9', 'src/third_party/dart/third_party/devtools': - {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:7421a2d5d67cbcdec92f1a2ac993b8b64b28d7ca'}]}, + {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:8be1bc8d6862a3fcf8f43917f6e0c783cac06d51'}]}, 'src/third_party/dart/third_party/pkg/args': Var('dart_git') + '/args.git@788d93541a578e49f066699e1584bc3ce591c376', @@ -397,7 +397,7 @@ deps = { Var('dart_git') + '/dart_style.git@a6ad7693555a9add6f98ad6fd94de80d35c89415', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@79c1675956f74b4e3f44134879beeb230a84bcd1', + Var('dart_git') + '/dartdoc.git@bf6080c8a12bf3a2f29f517d152bbd5fa1bb0a37', 'src/third_party/dart/third_party/pkg/file': Var('dart_git') + '/external/github.com/google/file.dart@3aa06490bf34bddf04c7ea964a50c177a4ca0de7', @@ -412,7 +412,7 @@ deps = { Var('dart_git') + '/html.git@327e37a6a4dd46599737ee982f280d73a8f646f7', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@7949d6f4a60bb5e9158da52910aa6bacda6b9286', + Var('dart_git') + '/http.git@280d3615a2d248d155e87766c9d9bcf586af2c3c', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@ba9d07f3596b24718ddf45c9e071d40879cca565', diff --git a/ci/licenses_golden/licenses_dart b/ci/licenses_golden/licenses_dart index 7506325a7aff7..56e2750fa7bd1 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 436d820942d64c56e10183515883c9b6 +Signature: 3b43e591f56158a01c82f09b4ee75b97 ==================================================================================================== LIBRARY: dart @@ -4737,7 +4737,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/bb65648e20e29abc47acf3dd984518d29fd625c3 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/52b05146758e77d548d67835863cd4a1307b30ae /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index 3376a60b8e33a..fa8890434b049 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -22574,6 +22574,37 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file @@ -22882,6 +22913,37 @@ shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file @@ -23054,6 +23116,55 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- boringssl Copyright (c) 2015, Google Inc. @@ -23104,6 +23215,37 @@ shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file @@ -23291,6 +23433,37 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file @@ -23762,6 +23935,37 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file @@ -24066,6 +24270,37 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- +pkg + +Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- dart Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file @@ -26833,6 +27068,37 @@ copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +pkg + +Copyright 2017, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -28107,6 +28373,37 @@ copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +pkg + +Copyright 2021, the Dart project authors. Please see the AUTHORS file +for details. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -31735,7 +32032,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/bb65648e20e29abc47acf3dd984518d29fd625c3 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/52b05146758e77d548d67835863cd4a1307b30ae /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From 666eeb675186ca896f28a0caaabe83e6d031f34e Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 14:46:05 -0700 Subject: [PATCH 32/49] Implement `Paint.from(other)` for `dart:ui`. (#51110) (Tenatively) Closes https://github.com/flutter/flutter/issues/142871. I personally think this is a reasonable request, and we (framework authors) can make some users happy in a fairly simple way (https://github.com/flutter/flutter/issues/142871, https://github.com/flutter/flutter/issues/40497). Some questions: 1. Is the web implementation good enough or would we want to "ship" with an optimized impl? 2. Can folks imagine other edge cases to test beyond correctness and deep/immutable copies? --- lib/ui/painting.dart | 16 +++++ lib/web_ui/lib/painting.dart | 29 ++++++++ lib/web_ui/test/ui/paint_test.dart | 48 +++++++++++++ testing/dart/canvas_test.dart | 105 +++++++++++++++++++++++++++++ 4 files changed, 198 insertions(+) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a2757b7359ce8..bfe9de5a854bb 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1092,6 +1092,22 @@ final class Paint { /// their defaults. Paint(); + /// Constructs a new [Paint] object with the same fields as [other]. + /// + /// Any changes made to the object returned will not affect [other], and + /// changes to [other] will not affect the object returned. + /// + /// Backends (for example web versus native) may have different performance + /// characteristics. If the code is performance-sensitive, consider profiling + /// and falling back to reusing a single [Paint] object if necessary. + Paint.from(Paint other) { + // Every field on Paint is deeply immutable, so to create a copy of a Paint + // object, we copy the underlying data buffer and the list of objects (which + // are also deeply immutable). + _data.buffer.asUint32List().setAll(0, other._data.buffer.asUint32List()); + _objects = other._objects?.toList(); + } + // Paint objects are encoded in two buffers: // // * _data is binary data in four-byte fields, each of which is either a diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index c050e43dec611..c7e1ff62c270a 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -217,6 +217,35 @@ enum Clip { abstract class Paint { factory Paint() => engine.renderer.createPaint(); + + factory Paint.from(Paint other) { + // This is less efficient than copying the underlying buffer or object but + // it's a reasonable default, as if a user wanted to implement a copy of a + // paint object themselves they are unable to do much better than this. + // + // TODO(matanlurey): Web team, if important to optimize, could: + // 1. Add a `engine.renderer.copyPaint` method. + // 2. Use the below code as the default implementation. + // 3. Have renderer-specific implementations override with optimized code. + final Paint paint = Paint(); + paint + ..blendMode = other.blendMode + ..color = other.color + ..colorFilter = other.colorFilter + ..filterQuality = other.filterQuality + ..imageFilter = other.imageFilter + ..invertColors = other.invertColors + ..isAntiAlias = other.isAntiAlias + ..maskFilter = other.maskFilter + ..shader = other.shader + ..strokeCap = other.strokeCap + ..strokeJoin = other.strokeJoin + ..strokeMiterLimit = other.strokeMiterLimit + ..strokeWidth = other.strokeWidth + ..style = other.style; + return paint; + } + BlendMode get blendMode; set blendMode(BlendMode value); PaintingStyle get style; diff --git a/lib/web_ui/test/ui/paint_test.dart b/lib/web_ui/test/ui/paint_test.dart index 2c34c77c020c6..a0264d7a98494 100644 --- a/lib/web_ui/test/ui/paint_test.dart +++ b/lib/web_ui/test/ui/paint_test.dart @@ -62,4 +62,52 @@ Future testMain() async { ')', ); }); + + test('.from copies every field', () { + final ui.Paint paint = ui.Paint(); + paint.blendMode = ui.BlendMode.darken; + paint.style = ui.PaintingStyle.fill; + paint.strokeWidth = 1.2; + paint.strokeCap = ui.StrokeCap.square; + paint.strokeJoin = ui.StrokeJoin.bevel; + paint.isAntiAlias = true; + paint.color = const ui.Color(0xaabbccdd); + paint.invertColors = true; + paint.shader = ui.Gradient.linear( + const ui.Offset(0.1, 0.2), + const ui.Offset(1.5, 1.6), + const [ + ui.Color(0xaabbccdd), + ui.Color(0xbbccddee), + ], + [0.3, 0.4], + ui.TileMode.decal, + ); + paint.maskFilter = const ui.MaskFilter.blur(ui.BlurStyle.normal, 1.7); + paint.filterQuality = ui.FilterQuality.high; + paint.colorFilter = const ui.ColorFilter.linearToSrgbGamma(); + paint.strokeMiterLimit = 1.8; + paint.imageFilter = ui.ImageFilter.blur( + sigmaX: 1.9, + sigmaY: 2.1, + tileMode: ui.TileMode.mirror, + ); + + final ui.Paint copy = ui.Paint.from(paint); + + expect(copy.blendMode, paint.blendMode); + expect(copy.style, paint.style); + expect(copy.strokeWidth, paint.strokeWidth); + expect(copy.strokeCap, paint.strokeCap); + expect(copy.strokeJoin, paint.strokeJoin); + expect(copy.isAntiAlias, paint.isAntiAlias); + expect(copy.color, paint.color); + expect(copy.invertColors, paint.invertColors); + expect(copy.shader, paint.shader); + expect(copy.maskFilter, paint.maskFilter); + expect(copy.filterQuality, paint.filterQuality); + expect(copy.colorFilter, paint.colorFilter); + expect(copy.strokeMiterLimit, paint.strokeMiterLimit); + expect(copy.imageFilter, paint.imageFilter); + }); } diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart index fe957e3340f12..b121a5d924052 100644 --- a/testing/dart/canvas_test.dart +++ b/testing/dart/canvas_test.dart @@ -1162,6 +1162,111 @@ void main() async { final Image image = await picture.toImage(200, 200); await comparer.addGoldenImage(image, 'text_decoration.png'); }); + + test('Paint, when copied, has equivalent fields', () { + final Paint paint = Paint() + ..color = const Color(0xFF0000FF) + ..strokeWidth = 10.0 + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round + ..style = PaintingStyle.stroke + ..blendMode = BlendMode.srcOver + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10.0) + ..filterQuality = FilterQuality.high + ..colorFilter = const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color) + ..imageFilter = ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0); + + final Paint paintCopy = Paint.from(paint); + expect(paintCopy.color, equals(const Color(0xFF0000FF))); + expect(paintCopy.strokeWidth, equals(10.0)); + expect(paintCopy.strokeCap, equals(StrokeCap.round)); + expect(paintCopy.strokeJoin, equals(StrokeJoin.round)); + expect(paintCopy.style, equals(PaintingStyle.stroke)); + expect(paintCopy.blendMode, equals(BlendMode.srcOver)); + expect(paintCopy.maskFilter, equals(const MaskFilter.blur(BlurStyle.normal, 10.0))); + expect(paintCopy.filterQuality, equals(FilterQuality.high)); + expect(paintCopy.colorFilter, equals(const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color))); + expect(paintCopy.imageFilter, equals(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0))); + }); + + test('Paint, when copied, does not mutate the original instance', () { + final Paint paint = Paint() + ..color = const Color(0xFF0000FF) + ..strokeWidth = 10.0 + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round + ..style = PaintingStyle.stroke + ..blendMode = BlendMode.srcOver + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10.0) + ..filterQuality = FilterQuality.high + ..colorFilter = const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color) + ..imageFilter = ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0); + + // Make a copy, and change every field of the copy. + Paint.from(paint) + ..color = const Color(0xFF00FF00) + ..strokeWidth = 20.0 + ..strokeCap = StrokeCap.butt + ..strokeJoin = StrokeJoin.bevel + ..style = PaintingStyle.fill + ..blendMode = BlendMode.srcIn + ..maskFilter = const MaskFilter.blur(BlurStyle.solid, 20.0) + ..filterQuality = FilterQuality.none + ..colorFilter = const ColorFilter.mode(Color(0xFFFF0000), BlendMode.modulate) + ..imageFilter = ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0); + + // The original paint should not have changed. + expect(paint.color, equals(const Color(0xFF0000FF))); + expect(paint.strokeWidth, equals(10.0)); + expect(paint.strokeCap, equals(StrokeCap.round)); + expect(paint.strokeJoin, equals(StrokeJoin.round)); + expect(paint.style, equals(PaintingStyle.stroke)); + expect(paint.blendMode, equals(BlendMode.srcOver)); + expect(paint.maskFilter, equals(const MaskFilter.blur(BlurStyle.normal, 10.0))); + expect(paint.filterQuality, equals(FilterQuality.high)); + expect(paint.colorFilter, equals(const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color))); + expect(paint.imageFilter, equals(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0))); + }); + + test('Paint, when copied, the original changing does not mutate the copy', () { + final Paint paint = Paint() + ..color = const Color(0xFF0000FF) + ..strokeWidth = 10.0 + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round + ..style = PaintingStyle.stroke + ..blendMode = BlendMode.srcOver + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10.0) + ..filterQuality = FilterQuality.high + ..colorFilter = const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color) + ..imageFilter = ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0); + + // Make a copy, and change every field of the original. + final Paint paintCopy = Paint.from(paint); + paint + ..color = const Color(0xFF00FF00) + ..strokeWidth = 20.0 + ..strokeCap = StrokeCap.butt + ..strokeJoin = StrokeJoin.bevel + ..style = PaintingStyle.fill + ..blendMode = BlendMode.srcIn + ..maskFilter = const MaskFilter.blur(BlurStyle.solid, 20.0) + ..filterQuality = FilterQuality.none + ..colorFilter = const ColorFilter.mode(Color(0xFFFF0000), BlendMode.modulate) + ..imageFilter = ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0); + + // The copy should not have changed. + expect(paintCopy.color, equals(const Color(0xFF0000FF))); + expect(paintCopy.strokeWidth, equals(10.0)); + expect(paintCopy.strokeCap, equals(StrokeCap.round)); + expect(paintCopy.strokeJoin, equals(StrokeJoin.round)); + expect(paintCopy.style, equals(PaintingStyle.stroke)); + expect(paintCopy.blendMode, equals(BlendMode.srcOver)); + expect(paintCopy.maskFilter, equals(const MaskFilter.blur(BlurStyle.normal, 10.0))); + expect(paintCopy.filterQuality, equals(FilterQuality.high)); + expect(paintCopy.colorFilter, equals(const ColorFilter.mode(Color(0xFF00FF00), BlendMode.color))); + expect(paintCopy.imageFilter, equals(ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0))); + }); } Matcher listEquals(ByteData expected) => (dynamic v) { From 8ec35b6d63ba5616110f649f2e333b313efec1fe Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:47:48 -0700 Subject: [PATCH 33/49] [Impeller] removed old blur detritus (#51779) [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- ci/licenses_golden/licenses_flutter | 10 +- impeller/entity/BUILD.gn | 4 +- impeller/entity/contents/content_context.cc | 4 - impeller/entity/contents/content_context.h | 28 +- .../shaders/gaussian_blur/gaussian_blur.glsl | 73 -- .../gaussian_blur_noalpha_decal.frag | 9 - .../gaussian_blur_noalpha_nodecal.frag | 9 - .../{gaussian_blur.vert => kernel.vert} | 0 impeller/tools/malioc.json | 1013 +++++------------ 9 files changed, 322 insertions(+), 828 deletions(-) delete mode 100644 impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl delete mode 100644 impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag delete mode 100644 impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag rename impeller/entity/shaders/gaussian_blur/{gaussian_blur.vert => kernel.vert} (100%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a08d4853afa14..5ee86025aa619 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -40037,11 +40037,8 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/conical_gradient_fill.frag + .. ORIGIN: ../../../flutter/impeller/entity/shaders/conical_gradient_ssbo_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/debug/checkerboard.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/debug/checkerboard.vert + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.glsl + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/points.comp + ../../../flutter/LICENSE @@ -42916,11 +42913,8 @@ FILE: ../../../flutter/impeller/entity/shaders/conical_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/conical_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/debug/checkerboard.frag FILE: ../../../flutter/impeller/entity/shaders/debug/checkerboard.vert -FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl -FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert -FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag -FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.glsl +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.vert FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag FILE: ../../../flutter/impeller/entity/shaders/geometry/points.comp diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index b4698a4f1e9d9..82b208479f146 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -25,11 +25,9 @@ impeller_shaders("entity_shaders") { "shaders/color_matrix_color_filter.frag", "shaders/color_matrix_color_filter.vert", "shaders/conical_gradient_fill.frag", - "shaders/gaussian_blur/gaussian_blur.vert", - "shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag", - "shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag", "shaders/gaussian_blur/kernel_decal.frag", "shaders/gaussian_blur/kernel_nodecal.frag", + "shaders/gaussian_blur/kernel.vert", "shaders/glyph_atlas.frag", "shaders/glyph_atlas_color.frag", "shaders/glyph_atlas.vert", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index f27096cd876d1..a127be44076c9 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -405,10 +405,6 @@ ContentContext::ContentContext( texture_strict_src_pipelines_.CreateDefault(*context_, options); position_uv_pipelines_.CreateDefault(*context_, options); tiled_texture_pipelines_.CreateDefault(*context_, options); - gaussian_blur_noalpha_decal_pipelines_.CreateDefault(*context_, - options_trianglestrip); - gaussian_blur_noalpha_nodecal_pipelines_.CreateDefault(*context_, - options_trianglestrip); kernel_decal_pipelines_.CreateDefault(*context_, options_trianglestrip); kernel_nodecal_pipelines_.CreateDefault(*context_, options_trianglestrip); border_mask_blur_pipelines_.CreateDefault(*context_, options_trianglestrip); diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 5f0380a15461b..ab84526ba5827 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -67,9 +67,7 @@ #include "impeller/entity/yuv_to_rgb_filter.frag.h" #include "impeller/entity/yuv_to_rgb_filter.vert.h" -#include "impeller/entity/gaussian_blur.vert.h" -#include "impeller/entity/gaussian_blur_noalpha_decal.frag.h" -#include "impeller/entity/gaussian_blur_noalpha_nodecal.frag.h" +#include "impeller/entity/kernel.vert.h" #include "impeller/entity/kernel_decal.frag.h" #include "impeller/entity/kernel_nodecal.frag.h" @@ -139,16 +137,10 @@ using PositionUVPipeline = RenderPipelineT; using TiledTexturePipeline = RenderPipelineT; -using GaussianBlurDecalPipeline = - RenderPipelineT; -using GaussianBlurPipeline = - RenderPipelineT; using KernelDecalPipeline = - RenderPipelineT; + RenderPipelineT; using KernelPipeline = - RenderPipelineT; + RenderPipelineT; using BorderMaskBlurPipeline = RenderPipelineT; using MorphologyFilterPipeline = @@ -523,16 +515,6 @@ class ContentContext { return GetPipeline(tiled_texture_pipelines_, opts); } - std::shared_ptr> GetGaussianBlurDecalPipeline( - ContentContextOptions opts) const { - return GetPipeline(gaussian_blur_noalpha_decal_pipelines_, opts); - } - - std::shared_ptr> GetGaussianBlurPipeline( - ContentContextOptions opts) const { - return GetPipeline(gaussian_blur_noalpha_nodecal_pipelines_, opts); - } - std::shared_ptr> GetKernelDecalPipeline( ContentContextOptions opts) const { return GetPipeline(kernel_decal_pipelines_, opts); @@ -977,10 +959,6 @@ class ContentContext { #endif // IMPELLER_ENABLE_OPENGLES mutable Variants position_uv_pipelines_; mutable Variants tiled_texture_pipelines_; - mutable Variants - gaussian_blur_noalpha_decal_pipelines_; - mutable Variants - gaussian_blur_noalpha_nodecal_pipelines_; mutable Variants kernel_decal_pipelines_; mutable Variants kernel_nodecal_pipelines_; mutable Variants border_mask_blur_pipelines_; diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl deleted file mode 100644 index ebf135a482328..0000000000000 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl +++ /dev/null @@ -1,73 +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. - -// 1D (directional) gaussian blur. -// -// Paths for future optimization: -// * Remove the uv bounds multiplier in SampleColor by adding optional -// support for SamplerAddressMode::ClampToBorder in the texture sampler. -// * Render both blur passes into a smaller texture than the source image -// (~1/radius size). -// * If doing the small texture render optimization, cache misses can be -// reduced in the first pass by sampling the source textures with a mip -// level of log2(min_radius). - -#include -#include -#include -#include - -uniform f16sampler2D texture_sampler; - -uniform BlurInfo { - f16vec2 blur_uv_offset; - - // The blur sigma and radius have a linear relationship which is defined - // host-side, but both are useful controls here. Sigma (pixels per standard - // deviation) is used to define the gaussian function itself, whereas the - // radius is used to limit how much of the function is integrated. - float blur_sigma; - float16_t blur_radius; - float16_t step_size; -} -blur_info; - -f16vec4 Sample(f16sampler2D tex, vec2 coords) { -#if ENABLE_DECAL_SPECIALIZATION - return IPHalfSampleDecal(tex, coords); -#else - return texture(tex, coords); -#endif -} - -in vec2 v_texture_coords; - -out f16vec4 frag_color; - -void main() { - f16vec4 total_color = f16vec4(0.0hf); - float16_t gaussian_integral = 0.0hf; - - // Step by 2.0 as a performance optimization, relying on bilinear filtering in - // the sampler to blend the texels. Typically the space between pixels is - // calculated so their blended amounts match the gaussian coefficients. This - // just uses 0.5 as an optimization until the gaussian coefficients are - // calculated and passed in from the cpu. - for (float16_t i = -blur_info.blur_radius; i <= blur_info.blur_radius; - i += blur_info.step_size) { - // Use the 32 bit Gaussian function because the 16 bit variation results in - // quality loss/visible banding. Also, 16 bit variation internally breaks - // down at a moderately high (but still reasonable) blur sigma of >255 when - // computing sigma^2 due to the exponent only having 5 bits. - float16_t gaussian = float16_t(IPGaussian(float(i), blur_info.blur_sigma)); - gaussian_integral += gaussian; - total_color += - gaussian * Sample(texture_sampler, // sampler - v_texture_coords + blur_info.blur_uv_offset * - i // texture coordinates - ); - } - - frag_color = total_color / gaussian_integral; -} diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag b/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag deleted file mode 100644 index 7bb1045e19dbc..0000000000000 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag +++ /dev/null @@ -1,9 +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. - -precision mediump float; - -#define ENABLE_DECAL_SPECIALIZATION 1 - -#include "gaussian_blur.glsl" diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag b/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag deleted file mode 100644 index 79d708e1dae36..0000000000000 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag +++ /dev/null @@ -1,9 +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. - -precision mediump float; - -#define ENABLE_DECAL_SPECIALIZATION 0 - -#include "gaussian_blur.glsl" diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert b/impeller/entity/shaders/gaussian_blur/kernel.vert similarity index 100% rename from impeller/entity/shaders/gaussian_blur/gaussian_blur.vert rename to impeller/entity/shaders/gaussian_blur/kernel.vert diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index faaffd82a987d..ae4d808c54a69 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -1153,263 +1153,6 @@ } } }, - "flutter/impeller/entity/gaussian_blur.vert.vkspv": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gaussian_blur.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": 30, - "work_registers_used": 32 - }, - "Varying": { - "fp16_arithmetic": 0, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.015625, - 0.015625, - 0.015625, - 0.0, - 3.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.015625, - 0.015625, - 0.015625, - 0.0, - 3.0, - 0.0 - ], - "total_bound_pipelines": [ - "load_store" - ], - "total_cycles": [ - 0.015625, - 0.015625, - 0.015625, - 0.0, - 3.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 22, - "work_registers_used": 8 - } - } - } - }, - "flutter/impeller/entity/gaussian_blur_noalpha_decal.frag.vkspv": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gaussian_blur_noalpha_decal.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": 42, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - null - ], - "longest_path_cycles": [ - null, - null, - null, - null, - null, - null, - null - ], - "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", - "load_store", - "varying", - "texture" - ], - "shortest_path_bound_pipelines": [ - "arith_total", - "arith_cvt" - ], - "shortest_path_cycles": [ - 0.109375, - 0.03125, - 0.109375, - 0.0625, - 0.0, - 0.0, - 0.0 - ], - "total_bound_pipelines": [ - "arith_total", - "arith_cvt", - "arith_sfu" - ], - "total_cycles": [ - 0.3125, - 0.203125, - 0.3125, - 0.3125, - 0.0, - 0.25, - 0.25 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 10, - "work_registers_used": 16 - } - } - } - }, - "flutter/impeller/entity/gaussian_blur_noalpha_nodecal.frag.vkspv": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gaussian_blur_noalpha_nodecal.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": 35, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - null - ], - "longest_path_cycles": [ - null, - null, - null, - null, - null, - null, - null - ], - "pipelines": [ - "arith_total", - "arith_fma", - "arith_cvt", - "arith_sfu", - "load_store", - "varying", - "texture" - ], - "shortest_path_bound_pipelines": [ - "arith_total", - "arith_cvt" - ], - "shortest_path_cycles": [ - 0.109375, - 0.03125, - 0.109375, - 0.0625, - 0.0, - 0.0, - 0.0 - ], - "total_bound_pipelines": [ - "varying", - "texture" - ], - "total_cycles": [ - 0.203125, - 0.203125, - 0.203125, - 0.125, - 0.0, - 0.25, - 0.25 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 10, - "work_registers_used": 13 - } - } - } - }, "flutter/impeller/entity/gles/advanced_blend.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -3083,27 +2826,33 @@ } } }, - "flutter/impeller/entity/gles/gaussian_blur.vert.gles": { + "flutter/impeller/entity/gles/glyph_atlas.frag.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/gaussian_blur.vert.gles", - "has_uniform_computation": true, - "type": "Vertex", - "variants": { - "Position": { - "fp16_arithmetic": 0, + "filename": "flutter/impeller/entity/gles/glyph_atlas.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": 100, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "load_store" + "varying" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.03125, + 0.03125, + 0.03125, 0.0, 0.0, - 2.0, - 0.0 + 0.5, + 0.25 ], "pipelines": [ "arith_total", @@ -3111,105 +2860,59 @@ "arith_cvt", "arith_sfu", "load_store", + "varying", "texture" ], "shortest_path_bound_pipelines": [ - "load_store" + "varying" ], "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.03125, + 0.03125, 0.0, - 2.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 22, - "work_registers_used": 32 - }, - "Varying": { - "fp16_arithmetic": 0, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.015625, - 0.015625, - 0.015625, 0.0, - 3.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.015625, - 0.015625, - 0.015625, 0.0, - 3.0, - 0.0 + 0.5, + 0.25 ], "total_bound_pipelines": [ - "load_store" + "varying" ], "total_cycles": [ - 0.015625, - 0.015625, - 0.015625, + 0.03125, + 0.03125, + 0.03125, 0.0, - 3.0, - 0.0 + 0.0, + 0.5, + 0.25 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 10, - "work_registers_used": 8 + "uniform_registers_used": 4, + "work_registers_used": 19 } } }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/gaussian_blur.vert.gles", + "filename": "flutter/impeller/entity/gles/glyph_atlas.frag.gles", "has_uniform_computation": false, - "type": "Vertex", + "type": "Fragment", "variants": { "Main": { "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "load_store" + "arithmetic", + "load_store", + "texture" ], "longest_path_cycles": [ - 2.9700000286102295, - 5.0, - 0.0 + 1.0, + 1.0, + 1.0 ], "pipelines": [ "arithmetic", @@ -3217,56 +2920,53 @@ "texture" ], "shortest_path_bound_pipelines": [ - "load_store" + "arithmetic", + "load_store", + "texture" ], "shortest_path_cycles": [ - 2.9700000286102295, - 5.0, - 0.0 + 1.0, + 1.0, + 1.0 ], "total_bound_pipelines": [ - "load_store" + "load_store", + "texture" ], "total_cycles": [ - 3.0, - 5.0, - 0.0 + 0.6666666865348816, + 1.0, + 1.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 6, + "uniform_registers_used": 0, "work_registers_used": 2 } } } }, - "flutter/impeller/entity/gles/gaussian_blur_noalpha_decal.frag.gles": { + "flutter/impeller/entity/gles/glyph_atlas.vert.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/gaussian_blur_noalpha_decal.frag.gles", - "has_side_effects": false, + "filename": "flutter/impeller/entity/gles/glyph_atlas.vert.gles", "has_uniform_computation": true, - "modifies_coverage": false, - "reads_color_buffer": false, - "type": "Fragment", - "uses_late_zs_test": false, - "uses_late_zs_update": false, + "type": "Vertex", "variants": { - "Main": { - "fp16_arithmetic": 70, + "Position": { + "fp16_arithmetic": 0, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - null + "load_store" ], "longest_path_cycles": [ - null, - null, - null, - null, - null, - null, - null + 0.515625, + 0.515625, + 0.140625, + 0.0, + 4.0, + 0.0 ], "pipelines": [ "arith_total", @@ -3274,178 +2974,105 @@ "arith_cvt", "arith_sfu", "load_store", - "varying", "texture" ], "shortest_path_bound_pipelines": [ - "arith_total", - "arith_cvt", - "arith_sfu" + "load_store" ], "shortest_path_cycles": [ - 0.0625, + 0.484375, + 0.484375, 0.03125, - 0.0625, - 0.0625, - 0.0, 0.0, + 4.0, 0.0 ], "total_bound_pipelines": [ - "arith_total", - "arith_sfu" + "load_store" ], "total_cycles": [ - 0.3125, - 0.234375, - 0.296875, - 0.3125, + 0.737500011920929, + 0.737500011920929, + 0.15625, 0.0, - 0.25, - 0.25 + 4.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/gaussian_blur_noalpha_decal.frag.gles", - "has_uniform_computation": false, - "type": "Fragment", - "variants": { - "Main": { + "uniform_registers_used": 48, + "work_registers_used": 32 + }, + "Varying": { + "fp16_arithmetic": 0, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - null + "load_store" ], "longest_path_cycles": [ - null, - null, - null - ], - "pipelines": [ - "arithmetic", - "load_store", - "texture" - ], - "shortest_path_bound_pipelines": [ - "arithmetic" - ], - "shortest_path_cycles": [ - 1.3200000524520874, - 1.0, + 0.15625, + 0.15625, + 0.0625, + 0.0, + 5.0, 0.0 ], - "total_bound_pipelines": [ - "arithmetic" - ], - "total_cycles": [ - 4.666666507720947, - 1.0, - 1.0 - ] - }, - "thread_occupancy": 100, - "uniform_registers_used": 1, - "work_registers_used": 3 - } - } - } - }, - "flutter/impeller/entity/gles/gaussian_blur_noalpha_nodecal.frag.gles": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/gaussian_blur_noalpha_nodecal.frag.gles", - "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": 66, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - null - ], - "longest_path_cycles": [ - null, - null, - null, - null, - null, - null, - null - ], "pipelines": [ "arith_total", "arith_fma", "arith_cvt", "arith_sfu", "load_store", - "varying", "texture" ], "shortest_path_bound_pipelines": [ - "arith_total", - "arith_cvt", - "arith_sfu" + "load_store" ], "shortest_path_cycles": [ - 0.0625, - 0.03125, - 0.0625, + 0.15625, + 0.15625, 0.0625, 0.0, - 0.0, + 5.0, 0.0 ], "total_bound_pipelines": [ - "varying", - "texture" + "load_store" ], "total_cycles": [ - 0.234375, - 0.234375, - 0.1875, - 0.125, + 0.15625, + 0.15625, + 0.0625, 0.0, - 0.25, - 0.25 + 5.0, + 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 8, - "work_registers_used": 19 + "uniform_registers_used": 18, + "work_registers_used": 16 } } }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/gaussian_blur_noalpha_nodecal.frag.gles", - "has_uniform_computation": false, - "type": "Fragment", + "filename": "flutter/impeller/entity/gles/glyph_atlas.vert.gles", + "has_uniform_computation": true, + "type": "Vertex", "variants": { "Main": { "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - null + "load_store" ], "longest_path_cycles": [ - null, - null, - null + 7.260000228881836, + 8.0, + 0.0 ], "pipelines": [ "arithmetic", @@ -3453,35 +3080,35 @@ "texture" ], "shortest_path_bound_pipelines": [ - "arithmetic" + "load_store" ], "shortest_path_cycles": [ - 1.3200000524520874, - 1.0, + 6.269999980926514, + 8.0, 0.0 ], "total_bound_pipelines": [ "arithmetic" ], "total_cycles": [ - 3.3333332538604736, - 1.0, - 1.0 + 9.333333015441895, + 8.0, + 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 1, - "work_registers_used": 2 + "uniform_registers_used": 13, + "work_registers_used": 3 } } } }, - "flutter/impeller/entity/gles/glyph_atlas.frag.gles": { + "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/glyph_atlas.frag.gles", + "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", "has_side_effects": false, - "has_uniform_computation": false, + "has_uniform_computation": true, "modifies_coverage": false, "reads_color_buffer": false, "type": "Fragment", @@ -3496,9 +3123,9 @@ "varying" ], "longest_path_cycles": [ - 0.03125, - 0.03125, - 0.03125, + 0.0625, + 0.0625, + 0.0625, 0.0, 0.0, 0.5, @@ -3517,11 +3144,11 @@ "varying" ], "shortest_path_cycles": [ - 0.03125, + 0.0625, + 0.0625, 0.03125, 0.0, 0.0, - 0.0, 0.5, 0.25 ], @@ -3529,9 +3156,9 @@ "varying" ], "total_cycles": [ - 0.03125, - 0.03125, - 0.03125, + 0.0625, + 0.0625, + 0.0625, 0.0, 0.0, 0.5, @@ -3547,7 +3174,7 @@ }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/glyph_atlas.frag.gles", + "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", "has_uniform_computation": false, "type": "Fragment", "variants": { @@ -3580,27 +3207,26 @@ 1.0 ], "total_bound_pipelines": [ - "load_store", - "texture" + "arithmetic" ], "total_cycles": [ - 0.6666666865348816, + 1.3333333730697632, 1.0, 1.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 0, + "uniform_registers_used": 1, "work_registers_used": 2 } } } }, - "flutter/impeller/entity/gles/glyph_atlas.vert.gles": { + "flutter/impeller/entity/gles/gradient_fill.vert.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/glyph_atlas.vert.gles", - "has_uniform_computation": true, + "filename": "flutter/impeller/entity/gles/gradient_fill.vert.gles", + "has_uniform_computation": false, "type": "Vertex", "variants": { "Position": { @@ -3611,62 +3237,11 @@ "load_store" ], "longest_path_cycles": [ - 0.515625, - 0.515625, + 0.140625, 0.140625, 0.0, - 4.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.484375, - 0.484375, - 0.03125, - 0.0, - 4.0, - 0.0 - ], - "total_bound_pipelines": [ - "load_store" - ], - "total_cycles": [ - 0.737500011920929, - 0.737500011920929, - 0.15625, - 0.0, - 4.0, - 0.0 - ] - }, - "stack_spill_bytes": 0, - "thread_occupancy": 100, - "uniform_registers_used": 48, - "work_registers_used": 32 - }, - "Varying": { - "fp16_arithmetic": 0, - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 0.15625, - 0.15625, - 0.0625, 0.0, - 5.0, + 2.0, 0.0 ], "pipelines": [ @@ -3681,105 +3256,44 @@ "load_store" ], "shortest_path_cycles": [ - 0.15625, - 0.15625, - 0.0625, + 0.140625, + 0.140625, 0.0, - 5.0, + 0.0, + 2.0, 0.0 ], "total_bound_pipelines": [ "load_store" ], "total_cycles": [ - 0.15625, - 0.15625, - 0.0625, + 0.140625, + 0.140625, 0.0, - 5.0, + 0.0, + 2.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 18, - "work_registers_used": 16 - } - } - }, - "Mali-T880": { - "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/glyph_atlas.vert.gles", - "has_uniform_computation": true, - "type": "Vertex", - "variants": { - "Main": { - "has_stack_spilling": false, - "performance": { - "longest_path_bound_pipelines": [ - "load_store" - ], - "longest_path_cycles": [ - 7.260000228881836, - 8.0, - 0.0 - ], - "pipelines": [ - "arithmetic", - "load_store", - "texture" - ], - "shortest_path_bound_pipelines": [ - "load_store" - ], - "shortest_path_cycles": [ - 6.269999980926514, - 8.0, - 0.0 - ], - "total_bound_pipelines": [ - "arithmetic" - ], - "total_cycles": [ - 9.333333015441895, - 8.0, - 0.0 - ] - }, - "thread_occupancy": 100, - "uniform_registers_used": 13, - "work_registers_used": 3 - } - } - } - }, - "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles": { - "Mali-G78": { - "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", - "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": 100, + "uniform_registers_used": 30, + "work_registers_used": 32 + }, + "Varying": { + "fp16_arithmetic": 0, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "varying" + "load_store" ], "longest_path_cycles": [ - 0.0625, - 0.0625, - 0.0625, - 0.0, + 0.125, + 0.125, 0.0, - 0.5, - 0.25 + 0.0625, + 3.0, + 0.0 ], "pipelines": [ "arith_total", @@ -3787,59 +3301,54 @@ "arith_cvt", "arith_sfu", "load_store", - "varying", "texture" ], "shortest_path_bound_pipelines": [ - "varying" + "load_store" ], "shortest_path_cycles": [ - 0.0625, - 0.0625, - 0.03125, - 0.0, + 0.125, + 0.125, 0.0, - 0.5, - 0.25 + 0.0625, + 3.0, + 0.0 ], "total_bound_pipelines": [ - "varying" + "load_store" ], "total_cycles": [ - 0.0625, - 0.0625, - 0.0625, - 0.0, + 0.125, + 0.125, 0.0, - 0.5, - 0.25 + 0.0625, + 3.0, + 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 4, - "work_registers_used": 19 + "uniform_registers_used": 18, + "work_registers_used": 11 } } }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/glyph_atlas_color.frag.gles", + "filename": "flutter/impeller/entity/gles/gradient_fill.vert.gles", "has_uniform_computation": false, - "type": "Fragment", + "type": "Vertex", "variants": { "Main": { "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ - "arithmetic", - "load_store", - "texture" + "load_store" ], "longest_path_cycles": [ - 1.0, - 1.0, - 1.0 + 3.299999952316284, + 4.0, + 0.0 ], "pipelines": [ "arithmetic", @@ -3847,36 +3356,34 @@ "texture" ], "shortest_path_bound_pipelines": [ - "arithmetic", - "load_store", - "texture" + "load_store" ], "shortest_path_cycles": [ - 1.0, - 1.0, - 1.0 + 3.299999952316284, + 4.0, + 0.0 ], "total_bound_pipelines": [ - "arithmetic" + "load_store" ], "total_cycles": [ - 1.3333333730697632, - 1.0, - 1.0 + 3.3333332538604736, + 4.0, + 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 1, + "uniform_registers_used": 8, "work_registers_used": 2 } } } }, - "flutter/impeller/entity/gles/gradient_fill.vert.gles": { + "flutter/impeller/entity/gles/kernel.vert.gles": { "Mali-G78": { "core": "Mali-G78", - "filename": "flutter/impeller/entity/gles/gradient_fill.vert.gles", - "has_uniform_computation": false, + "filename": "flutter/impeller/entity/gles/kernel.vert.gles", + "has_uniform_computation": true, "type": "Vertex", "variants": { "Position": { @@ -3927,7 +3434,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 30, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -3938,10 +3445,10 @@ "load_store" ], "longest_path_cycles": [ - 0.125, - 0.125, + 0.015625, + 0.015625, + 0.015625, 0.0, - 0.0625, 3.0, 0.0 ], @@ -3957,10 +3464,10 @@ "load_store" ], "shortest_path_cycles": [ - 0.125, - 0.125, + 0.015625, + 0.015625, + 0.015625, 0.0, - 0.0625, 3.0, 0.0 ], @@ -3968,24 +3475,24 @@ "load_store" ], "total_cycles": [ - 0.125, - 0.125, + 0.015625, + 0.015625, + 0.015625, 0.0, - 0.0625, 3.0, 0.0 ] }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 18, - "work_registers_used": 11 + "uniform_registers_used": 10, + "work_registers_used": 8 } } }, "Mali-T880": { "core": "Mali-T880", - "filename": "flutter/impeller/entity/gles/gradient_fill.vert.gles", + "filename": "flutter/impeller/entity/gles/kernel.vert.gles", "has_uniform_computation": false, "type": "Vertex", "variants": { @@ -3996,8 +3503,8 @@ "load_store" ], "longest_path_cycles": [ - 3.299999952316284, - 4.0, + 2.9700000286102295, + 5.0, 0.0 ], "pipelines": [ @@ -4009,21 +3516,21 @@ "load_store" ], "shortest_path_cycles": [ - 3.299999952316284, - 4.0, + 2.9700000286102295, + 5.0, 0.0 ], "total_bound_pipelines": [ "load_store" ], "total_cycles": [ - 3.3333332538604736, - 4.0, + 3.0, + 5.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 8, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -8076,6 +7583,118 @@ } } }, + "flutter/impeller/entity/kernel.vert.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/kernel.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": 30, + "work_registers_used": 32 + }, + "Varying": { + "fp16_arithmetic": 0, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + "load_store" + ], + "longest_path_cycles": [ + 0.015625, + 0.015625, + 0.015625, + 0.0, + 3.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.015625, + 0.015625, + 0.015625, + 0.0, + 3.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.015625, + 0.015625, + 0.015625, + 0.0, + 3.0, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 22, + "work_registers_used": 8 + } + } + } + }, "flutter/impeller/entity/kernel_decal.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", From 0ca0ef69a702eff41b601f1229c9e820e371ca27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:58:14 -0700 Subject: [PATCH 34/49] [Windows] Fix EGL surface destruction race (#51781) This fixes the `WindowsTest.EngineCanTransitionToHeadless` flakiness reported by @matanlurey. EGL surfaces can only be used by a single thread at a time. Concurrent operations are unsafe. Previously, the EGL surface was destroyed on the platform thread. This was safe as this always happened after the engine was shutdown and the raster thread was stopped. However, in a multi-view world a view can be destroyed while the engine is running. There may be pending raster tasks that operate on the render surface. Thus, the EGL surfaces should be destroyed on the raster thread when it is available. This bug was introduced by https://github.com/flutter/engine/pull/51681 Part of https://github.com/flutter/flutter/issues/142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../platform/windows/flutter_windows_view.cc | 28 +++++++++--- shell/platform/windows/flutter_windows_view.h | 3 -- .../windows/flutter_windows_view_unittests.cc | 45 +++++++++++++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 815cbaa3bb4f8..93f523194714a 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -7,7 +7,9 @@ #include #include "flutter/common/constants.h" +#include "flutter/fml/make_copyable.h" #include "flutter/fml/platform/win/wstring_conversion.h" +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/platform/common/accessibility_bridge.h" #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h" #include "flutter/shell/platform/windows/text_input_plugin.h" @@ -81,6 +83,22 @@ void UpdateVsync(const FlutterWindowsEngine& engine, } } +/// Destroys a rendering surface that backs a Flutter view. +void DestroyWindowSurface(const FlutterWindowsEngine& engine, + std::unique_ptr surface) { + // EGL surfaces are used on the raster thread if the engine is running. + // There may be pending raster tasks that use this surface. Destroy the + // surface on the raster thread to avoid concurrent uses. + if (engine.running()) { + engine.PostRasterThreadTask(fml::MakeCopyable( + [surface = std::move(surface)] { surface->Destroy(); })); + } else { + // There's no raster thread if engine isn't running. The surface can be + // destroyed on the platform thread. + surface->Destroy(); + } +} + } // namespace FlutterWindowsView::FlutterWindowsView( @@ -105,7 +123,9 @@ FlutterWindowsView::~FlutterWindowsView() { // Notify the engine the view's child window will no longer be visible. engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide); - DestroyRenderSurface(); + if (surface_) { + DestroyWindowSurface(*engine_, std::move(surface_)); + } } bool FlutterWindowsView::OnEmptyFrameGenerated() { @@ -706,12 +726,6 @@ bool FlutterWindowsView::ResizeRenderSurface(size_t width, size_t height) { return true; } -void FlutterWindowsView::DestroyRenderSurface() { - if (surface_) { - surface_->Destroy(); - } -} - egl::WindowSurface* FlutterWindowsView::surface() const { return surface_.get(); } diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 8cd4e5e71312b..782e63ad53136 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -50,9 +50,6 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // Should be called before calling FlutterEngineRun using this view. void CreateRenderSurface(); - // Destroys current rendering surface if one has been allocated. - void DestroyRenderSurface(); - // Get the EGL surface that backs the Flutter view. // // This might be nullptr or an invalid surface. diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index b4bb9a4789d90..c22459f32bd3d 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -264,6 +264,12 @@ TEST(FlutterWindowsViewTest, Shutdown) { InSequence s; EXPECT_CALL(*engine_ptr, running).WillOnce(Return(true)); EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1); + EXPECT_CALL(*engine_ptr, running).WillOnce(Return(true)); + EXPECT_CALL(*engine_ptr, PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); } } @@ -825,7 +831,14 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { auto windows_proc_table = std::make_shared>(); std::unique_ptr engine = GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -883,7 +896,14 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { auto windows_proc_table = std::make_shared>(); std::unique_ptr engine = GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -940,7 +960,14 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { // https://github.com/flutter/flutter/issues/141855 TEST(FlutterWindowsViewTest, WindowResizeRace) { std::unique_ptr engine = GetTestEngine(); + EngineModifier engine_modifier(engine.get()); + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -980,7 +1007,14 @@ TEST(FlutterWindowsViewTest, WindowResizeRace) { // even though EGL initialized successfully. TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) { std::unique_ptr engine = GetTestEngine(); + EngineModifier engine_modifier(engine.get()); + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -1477,6 +1511,11 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(false)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); + EXPECT_CALL(*engine.get(), PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1519,6 +1558,12 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(true)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); + + EXPECT_CALL(*engine.get(), PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; From 0a751669e722481c2848a287b47f25d741667746 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 18:19:52 -0400 Subject: [PATCH 35/49] Roll Skia from a12e40efacea to df005a80da32 (1 revision) (#51777) https://skia.googlesource.com/skia.git/+log/a12e40efacea..df005a80da32 2024-03-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from f91c2fe47c47 to b203847466b0 (3 revisions) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e4ef0549face9..fc1dbbb73b792 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'a12e40efacea22602d73e44ffb0d283ea156e11a', + 'skia_revision': 'df005a80da32afe82a86c1c181a36f586e81be99', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 221b49ae4a82dd77d4820fc9527ded491d8efe4d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 19:43:16 -0400 Subject: [PATCH 36/49] Roll Skia from df005a80da32 to 7338f5521e05 (11 revisions) (#51791) https://skia.googlesource.com/skia.git/+log/df005a80da32..7338f5521e05 2024-03-29 jvanverth@google.com [graphite] Implement missing YUV features. 2024-03-29 lovisolo@google.com [bazel] Rename //tools/sk_app:sk_app to //tools/sk_app:legacy_sk_app. 2024-03-29 lovisolo@google.com [bazel] Add //example:hello_world_gl target. 2024-03-29 egdaniel@google.com [graphite] Add query for compression type on TextureInfo. 2024-03-29 robertphillips@google.com Revert "[graphite] Use X-macro to get better UniqueKey printouts" 2024-03-29 robertphillips@google.com [graphite] Use X-macro to get better UniqueKey printouts 2024-03-29 bungeman@google.com [icc] Use namespace, remove static 2024-03-29 robertphillips@google.com [graphite] Move some ColorFilter factory functions to a private namespace 2024-03-29 egdaniel@google.com Update Viewer to allow Graphite pixel zoom to read pixels. 2024-03-29 bungeman@google.com [paragraph] Clean up ResourceFontCollection debugfs 2024-03-29 ccameron@chromium.org SkICC: Update tone mapping If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index fc1dbbb73b792..4c373791d4d43 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'df005a80da32afe82a86c1c181a36f586e81be99', + 'skia_revision': '7338f5521e05a62db4bb920e15dc17a67f4b7405', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5cdd9ee6013a2..fb93ea6185333 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 44e8cbcaed3b62ad7ea9dd0ddffa40ec +Signature: a5548041dd7d90f3a435c91bd478cbe6 ==================================================================================================== LIBRARY: etc1 From dce6ce366c7416a33ea4ff306514393fe37f77b4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 21:02:04 -0400 Subject: [PATCH 37/49] Roll Skia from 7338f5521e05 to ab0f4a038cec (1 revision) (#51793) https://skia.googlesource.com/skia.git/+log/7338f5521e05..ab0f4a038cec 2024-03-29 lovisolo@google.com [bazel] Rename //tools/window:window to //tools/window:legacy_window. If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4c373791d4d43..6f97d6f061d84 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '7338f5521e05a62db4bb920e15dc17a67f4b7405', + 'skia_revision': 'ab0f4a038cec4832539b0caace11d1cf42024603', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 0519838721c698f91be623dd91b807adf8c174f2 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 29 Mar 2024 18:14:23 -0700 Subject: [PATCH 38/49] Add more Java and Dart logging to `scenario_app` (for now) (#51789) Work towards https://github.com/flutter/flutter/issues/145988. ... as well as handle `sigTerm` (perhaps would help us actually write out logs? we'll see) --- .../ExternalTextureFlutterActivity.java | 2 + .../scenarios/TestableFlutterActivity.java | 3 + .../scenario_app/bin/run_android_tests.dart | 13 +++- testing/scenario_app/lib/main.dart | 6 ++ .../tool/deflake_android_tests.sh | 73 +++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100755 testing/scenario_app/tool/deflake_android_tests.sh diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java index 753f2e2690fb8..e363680777b9d 100644 --- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java +++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java @@ -91,6 +91,8 @@ public void waitUntilFlutterRendered() { super.waitUntilFlutterRendered(); try { + // TODO: Remove after debugging https://github.com/flutter/flutter/issues/145988. + io.flutter.Log.i("Scenarios", "waitUntilFlutterRendered() | firstFrameLatch"); firstFrameLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java index 69c9dd0260353..bb163be4defc9 100644 --- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java +++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java @@ -8,6 +8,7 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import io.flutter.Log; import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.engine.FlutterEngine; import java.util.concurrent.CountDownLatch; @@ -44,6 +45,8 @@ protected void notifyFlutterRendered() { public void waitUntilFlutterRendered() { try { + // TODO: Remove after debugging https://github.com/flutter/flutter/issues/145988. + Log.i("Scenarios", "waitUntilFlutterRendered() | flutterUiRenderedLatch"); flutterUiRenderedLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); diff --git a/testing/scenario_app/bin/run_android_tests.dart b/testing/scenario_app/bin/run_android_tests.dart index 669a255440f06..c0b8ffaf4b0cc 100644 --- a/testing/scenario_app/bin/run_android_tests.dart +++ b/testing/scenario_app/bin/run_android_tests.dart @@ -61,12 +61,23 @@ void main(List args) async { // Capture CTRL-C. late final StreamSubscription onSigint; + + // Capture requested termination. The goal is to catch timeouts. + late final StreamSubscription onSigterm; + void cancelSignalHandlers() { + onSigint.cancel(); + onSigterm.cancel(); + } runZonedGuarded( () async { onSigint = ProcessSignal.sigint.watch().listen((_) { - onSigint.cancel(); + cancelSignalHandlers(); panic(['Received SIGINT']); }); + onSigterm = ProcessSignal.sigterm.watch().listen((_) { + cancelSignalHandlers(); + panic(['Received SIGTERM']); + }); await _run( verbose: options.verbose, outDir: Directory(options.outDir), diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index 5e76f1d7306bf..080959becce46 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -92,10 +92,16 @@ void _onBeginFrame(Duration duration) { return; } currentScenario!.onBeginFrame(duration); + + // TODO(team): Remove after debugging https://github.com/flutter/flutter/issues/145988. + print('onBeginFrame: $duration'); } void _onDrawFrame() { currentScenario?.onDrawFrame(); + + // TODO(team): Remove after debugging https://github.com/flutter/flutter/issues/145988. + print('onDrawFrame'); } void _onMetricsChanged() { diff --git a/testing/scenario_app/tool/deflake_android_tests.sh b/testing/scenario_app/tool/deflake_android_tests.sh new file mode 100755 index 0000000000000..7940e00ff5dc7 --- /dev/null +++ b/testing/scenario_app/tool/deflake_android_tests.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# 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. + +set -e + +# Needed because if it is set, cd may print the path it changed to. +unset CDPATH + +# On Mac OS, readlink -f doesn't work, so follow_links traverses the path one +# link at a time, and then cds into the link destination and find out where it +# ends up. +# +# The function is enclosed in a subshell to avoid changing the working directory +# of the caller. +function follow_links() ( + cd -P "$(dirname -- "$1")" + file="$PWD/$(basename -- "$1")" + while [[ -L "$file" ]]; do + cd -P "$(dirname -- "$file")" + file="$(readlink -- "$file")" + cd -P "$(dirname -- "$file")" + file="$PWD/$(basename -- "$file")" + done + echo "$file" +) + +SCRIPT_DIR=$(follow_links "$(dirname -- "${BASH_SOURCE[0]}")") +ENGINE_DIR="$(cd "$SCRIPT_DIR/../../.."; pwd -P)" + +# Find the Dart executable. +case "$(uname -s)" in + Linux) + OS="linux" + ;; + Darwin) + OS="macos" + ;; + *) + echo "The host platform is not supported by this tool" + exit 1 +esac + +case "$(uname -m)" in + arm64) + CPU="arm64" + ;; + x86_64) + CPU="x64" + ;; + *) + echo "The host platform is not supported by this tool" + exit 1 +esac + +PLATFORM="${OS}-${CPU}" +DART_SDK_DIR="${ENGINE_DIR}/prebuilts/${PLATFORM}/dart-sdk" +DART="${DART_SDK_DIR}/bin/dart" + +# Run the tool indefinitely until there is an error. +COUNT=0 +while true; do + COUNT=$((COUNT + 1)) + echo "Running test iteration $COUNT" + "$DART" "$SCRIPT_DIR/bin/run_android_tests.dart" "$@" + # Break if non-zero exit code. + if [ $? -ne 0 ]; then + echo "Error running tests. Exiting." + break + fi +done From 5df1042cd92776271aaa8d98d5b01284e1fa9061 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 21:52:51 -0400 Subject: [PATCH 39/49] Roll Dart SDK from 52b05146758e to 572de60e008a (1 revision) (#51794) https://dart.googlesource.com/sdk.git/+log/52b05146758e..572de60e008a 2024-03-29 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-3.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC dart-vm-team@google.com,jacksongardner@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_dart | 4 ++-- sky/packages/sky_engine/LICENSE | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 6f97d6f061d84..7e7069afde6ef 100644 --- a/DEPS +++ b/DEPS @@ -62,7 +62,7 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': '52b05146758e77d548d67835863cd4a1307b30ae', + 'dart_revision': '572de60e008a31dcff04f38365d8dcc06a8bd312', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_dart b/ci/licenses_golden/licenses_dart index 56e2750fa7bd1..73445766e448b 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 3b43e591f56158a01c82f09b4ee75b97 +Signature: 07322c3cd592bb2895617ede8cff5e00 ==================================================================================================== LIBRARY: dart @@ -4737,7 +4737,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/52b05146758e77d548d67835863cd4a1307b30ae +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/572de60e008a31dcff04f38365d8dcc06a8bd312 /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index fa8890434b049..05a0f7494d78e 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32032,7 +32032,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/52b05146758e77d548d67835863cd4a1307b30ae +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/572de60e008a31dcff04f38365d8dcc06a8bd312 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From df581c316485e48e1798f479b5d29d826df2d0e0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 29 Mar 2024 22:17:04 -0400 Subject: [PATCH 40/49] Roll Skia from ab0f4a038cec to 7dc399e01f98 (2 revisions) (#51795) https://skia.googlesource.com/skia.git/+log/ab0f4a038cec..7dc399e01f98 2024-03-30 lovisolo@google.com [bazel] Define //tools/sk_app:sk_app modular build target. 2024-03-29 lovisolo@google.com [bazel] Define //tools/window:window modular build target. If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7e7069afde6ef..1ed103f6498f4 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'ab0f4a038cec4832539b0caace11d1cf42024603', + 'skia_revision': '7dc399e01f9869916dc9520add83a6c4304024c4', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 52e3d2fa171ef60fc162592b981ebd66b65bdc1f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 30 Mar 2024 00:19:37 -0400 Subject: [PATCH 41/49] Roll Fuchsia Linux SDK from 3vgfbp1vjXkdMZ09m... to wrbGDfD0BEOBXEGMK... (#51797) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter-engine Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1ed103f6498f4..30940b006727a 100644 --- a/DEPS +++ b/DEPS @@ -1024,7 +1024,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '3vgfbp1vjXkdMZ09mxspfRoiZfpVNzbnbC3cIjmtgrIC' + 'version': 'wrbGDfD0BEOBXEGMKeW2Cz5IQvnNWzvl5bDD3QMS5MYC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 0d60d82ecb06d..e168aff350013 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 12c107654d7b2e153c88680199c652bb +Signature: 4549aa95df9777c79b3808b31871af49 ==================================================================================================== LIBRARY: fuchsia_sdk From 08eb5ad6e498cbcf11060a857340141d0b557b56 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 30 Mar 2024 00:22:51 -0400 Subject: [PATCH 42/49] Roll Skia from 7dc399e01f98 to 0970776d543a (1 revision) (#51796) https://skia.googlesource.com/skia.git/+log/7dc399e01f98..0970776d543a 2024-03-30 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from b203847466b0 to 778a83fe011e (3 revisions) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,jamesgk@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 30940b006727a..b1ecc25aa6689 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '7dc399e01f9869916dc9520add83a6c4304024c4', + 'skia_revision': '0970776d543abfaf8f6bb57cc5fad3a5222759b6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 3588d31a98f6c2a1949132e1cf610265b04185a1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 30 Mar 2024 03:00:30 -0400 Subject: [PATCH 43/49] Roll Dart SDK from 572de60e008a to b735974580e7 (2 revisions) (#51799) https://dart.googlesource.com/sdk.git/+log/572de60e008a..b735974580e7 2024-03-30 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-5.0.dev 2024-03-30 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-4.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC dart-vm-team@google.com,jacksongardner@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_dart | 4 ++-- sky/packages/sky_engine/LICENSE | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index b1ecc25aa6689..b580bee80fc0c 100644 --- a/DEPS +++ b/DEPS @@ -62,7 +62,7 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': '572de60e008a31dcff04f38365d8dcc06a8bd312', + 'dart_revision': 'b735974580e7ad7461abf8175fec2fb27fc8b8e7', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_dart b/ci/licenses_golden/licenses_dart index 73445766e448b..cdfa227d1830e 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 07322c3cd592bb2895617ede8cff5e00 +Signature: eb8947e8b8a95e03ffee30cd064de078 ==================================================================================================== LIBRARY: dart @@ -4737,7 +4737,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/572de60e008a31dcff04f38365d8dcc06a8bd312 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/b735974580e7ad7461abf8175fec2fb27fc8b8e7 /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index 05a0f7494d78e..dce01614b1516 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32032,7 +32032,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/572de60e008a31dcff04f38365d8dcc06a8bd312 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/b735974580e7ad7461abf8175fec2fb27fc8b8e7 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From 2decefb00d1edcfb33b283f2b055a7744ea7f05a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 31 Mar 2024 01:40:22 -0400 Subject: [PATCH 44/49] Roll Fuchsia Linux SDK from wrbGDfD0BEOBXEGMK... to TXxMINUq7JduIRX8K... (#51801) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter-engine Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b580bee80fc0c..dfc78e92f6074 100644 --- a/DEPS +++ b/DEPS @@ -1024,7 +1024,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'wrbGDfD0BEOBXEGMKeW2Cz5IQvnNWzvl5bDD3QMS5MYC' + 'version': 'TXxMINUq7JduIRX8KEopRJ8DWvKc7M-QEoRRZAzxVp4C' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index e168aff350013..8a88f493c2451 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 4549aa95df9777c79b3808b31871af49 +Signature: a70195cba68c034d88ad6943cbcbd497 ==================================================================================================== LIBRARY: fuchsia_sdk From 34081fea4d5906921d1c54b0b46625041dff0a65 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 31 Mar 2024 03:28:38 -0400 Subject: [PATCH 45/49] Roll Skia from 0970776d543a to c61843470d89 (1 revision) (#51802) https://skia.googlesource.com/skia.git/+log/0970776d543a..c61843470d89 2024-03-31 skia-autoroll@skia-public.iam.gserviceaccount.com Roll SK Tool from 341432c665a4 to df0949e75440 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC brianosman@google.com,jacksongardner@google.com,kjlubick@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index dfc78e92f6074..495ab629e9d14 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '0970776d543abfaf8f6bb57cc5fad3a5222759b6', + 'skia_revision': 'c61843470d89de81c571d87ed2c810911edeb1a3', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 9689390986b7b7547a46e053d6e20d2993449899 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Sun, 31 Mar 2024 10:20:44 -0700 Subject: [PATCH 46/49] Finish clangd testing. (#51786) Closes https://github.com/flutter/flutter/issues/141641, yay we done! --------- Co-authored-by: Zachary Anderson --- .ci.yaml | 1 - ci/builders/mac_unopt_debug_no_rbe.json | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index c770736d3b47e..e84001fada595 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -368,7 +368,6 @@ targets: - os=Mac-13 - name: Linux mac_clangd - bringup: true recipe: engine_v2/engine_v2 # Avoid using a Mac orchestrator to save ~5 minutes of Mac host time. drone_dimensions: diff --git a/ci/builders/mac_unopt_debug_no_rbe.json b/ci/builders/mac_unopt_debug_no_rbe.json index af2acdd1950f1..9d31974457109 100644 --- a/ci/builders/mac_unopt_debug_no_rbe.json +++ b/ci/builders/mac_unopt_debug_no_rbe.json @@ -32,6 +32,11 @@ "config": "mac_unopt_debug_no_rbe", "targets": ["flutter/tools/font_subset"] }, + "properties": { + "$flutter/osx_sdk": { + "sdk_version": "15a240d" + } + }, "tests": [ { "language": "dart", From 4f6b832c8e333775f2c217a821050543a110826e Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Sun, 31 Mar 2024 19:43:02 +0000 Subject: [PATCH 47/49] Prefix non-local build config names with ci/ (#51474) Part 1 of https://github.com/flutter/flutter/issues/145263 This PR updates the names of builds outside of `local_engine.json` to be prefixed with the string `ci/` (or `ci\` on Windows). For better or worse, the "name" field of a build is used to construct a path used as the source directory of a copy operation (I think the CAS archive step?). Because of that, changing the name of a build also requires updating the build output directory of the ninja build. This PR also adds tests to make sure the naming of these builds remains consistent. --- build/copy_info_plist.py | 9 +- ci/analyze.sh | 7 +- ci/builders/linux_android_aot_engine.json | 123 ++++++++++-------- ci/builders/linux_android_debug_engine.json | 93 +++++++------ ci/builders/linux_android_emulator.json | 18 +-- ci/builders/linux_android_emulator_skia.json | 10 +- ci/builders/linux_arm_host_engine.json | 42 +++--- ci/builders/linux_clang_tidy.json | 44 +++---- ci/builders/linux_fuchsia.json | 104 +++++++++------ ci/builders/linux_host_desktop_engine.json | 36 ++--- ci/builders/linux_host_engine.json | 57 ++++---- ci/builders/linux_unopt.json | 42 +++--- ci/builders/linux_unopt_debug_no_rbe.json | 11 +- ci/builders/mac_android_aot_engine.json | 72 +++++----- ci/builders/mac_clang_tidy.json | 56 ++++---- ci/builders/mac_host_engine.json | 115 ++++++++-------- ci/builders/mac_impeller_cmake_example.json | 3 +- ci/builders/mac_ios_engine.json | 83 +++++++----- ci/builders/mac_unopt.json | 76 ++++++----- ci/builders/mac_unopt_debug_no_rbe.json | 11 +- ci/builders/standalone/linux_benchmarks.json | 16 ++- ci/builders/standalone/windows_unopt.json | 8 +- ci/builders/windows_android_aot_engine.json | 72 +++++----- ci/builders/windows_arm_host_engine.json | 46 ++++--- ci/builders/windows_host_engine.json | 48 ++++--- testing/BUILD.gn | 3 +- testing/benchmark/generate_metrics.sh | 22 ++-- testing/benchmark/upload_metrics.sh | 21 +-- testing/dart/BUILD.gn | 2 +- testing/fuchsia/run_tests.py | 2 +- testing/run_tests.py | 7 +- tools/clang_tidy/test/clang_tidy_test.dart | 1 + tools/clangd_check/bin/main.dart | 3 +- tools/fuchsia/build_fuchsia_artifacts.py | 2 +- tools/pkg/engine_build_configs/bin/check.dart | 97 ++++++++++++-- 35 files changed, 807 insertions(+), 555 deletions(-) diff --git a/build/copy_info_plist.py b/build/copy_info_plist.py index d812edacf06a1..feedab7b9a77e 100644 --- a/build/copy_info_plist.py +++ b/build/copy_info_plist.py @@ -8,8 +8,6 @@ Copies the Info.plist and adds extra fields to it like the git hash of the engine. -Precondition: $CWD/../../flutter is the path to the flutter engine repo. - usage: copy_info_plist.py --source --destination --minversion= """ @@ -20,10 +18,13 @@ import git_revision +_script_dir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..')) +_src_root_dir = os.path.join(_script_dir, '..', '..') + def get_clang_version(): clang_executable = str( - os.path.join('..', '..', 'flutter', 'buildtools', 'mac-x64', 'clang', 'bin', 'clang++') + os.path.join(_src_root_dir, 'flutter', 'buildtools', 'mac-x64', 'clang', 'bin', 'clang++') ) version = subprocess.check_output([clang_executable, '--version']) return version.splitlines()[0] @@ -47,7 +48,7 @@ def main(): args = parser.parse_args() text = open(args.source).read() - engine_path = os.path.join(os.getcwd(), '..', '..', 'flutter') + engine_path = os.path.join(_src_root_dir, 'flutter') revision = git_revision.get_repository_version(engine_path) clang_version = get_clang_version() text = text.format(revision=revision, clang_version=clang_version, min_version=args.minversion) diff --git a/ci/analyze.sh b/ci/analyze.sh index 30946e7529f28..e92ad3930398a 100755 --- a/ci/analyze.sh +++ b/ci/analyze.sh @@ -35,9 +35,12 @@ FLUTTER_DIR="$SRC_DIR/flutter" # directory. If not specified, we default to the build output for # host_debug_unopt. if [[ $# -eq 0 ]] ; then -DART_BIN="$SRC_DIR/out/host_debug_unopt/dart-sdk/bin" + DART_BIN="$SRC_DIR/out/host_debug_unopt/dart-sdk/bin" + if [[ ! -d "$DART_BIN" ]]; then + DART_BIN="$SRC_DIR/out/ci/host_debug_unopt/dart-sdk/bin" + fi else -DART_BIN="$1" + DART_BIN="$1" fi DART="$DART_BIN/dart" diff --git a/ci/builders/linux_android_aot_engine.json b/ci/builders/linux_android_aot_engine.json index d242283c719e4..116e0fc4d4a75 100644 --- a/ci/builders/linux_android_aot_engine.json +++ b/ci/builders/linux_android_aot_engine.json @@ -3,14 +3,14 @@ { "archives": [ { - "name": "android_profile", + "name": "ci/android_profile", "type": "gcs", - "base_path": "out/android_profile/zip_archives/", + "base_path": "out/ci/android_profile/zip_archives/", "include_paths": [ - "out/android_profile/zip_archives/android-arm-profile/artifacts.zip", - "out/android_profile/zip_archives/android-arm-profile/linux-x64.zip", - "out/android_profile/zip_archives/android-arm-profile/symbols.zip", - "out/android_profile/zip_archives/download.flutter.io" + "out/ci/android_profile/zip_archives/android-arm-profile/artifacts.zip", + "out/ci/android_profile/zip_archives/android-arm-profile/linux-x64.zip", + "out/ci/android_profile/zip_archives/android-arm-profile/symbols.zip", + "out/ci/android_profile/zip_archives/download.flutter.io" ], "realm": "production" } @@ -23,6 +23,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile", "--runtime-mode", "profile", "--android", @@ -31,9 +33,9 @@ "--rbe", "--no-goma" ], - "name": "android_profile", + "name": "ci/android_profile", "ninja": { - "config": "android_profile", + "config": "ci/android_profile", "targets": [ "default", "clang_x64/gen_snapshot", @@ -45,14 +47,14 @@ { "archives": [ { - "name": "android_release", + "name": "ci/android_release", "type": "gcs", - "base_path": "out/android_release/zip_archives/", + "base_path": "out/ci/android_release/zip_archives/", "include_paths": [ - "out/android_release/zip_archives/android-arm-release/artifacts.zip", - "out/android_release/zip_archives/android-arm-release/linux-x64.zip", - "out/android_release/zip_archives/android-arm-release/symbols.zip", - "out/android_release/zip_archives/download.flutter.io" + "out/ci/android_release/zip_archives/android-arm-release/artifacts.zip", + "out/ci/android_release/zip_archives/android-arm-release/linux-x64.zip", + "out/ci/android_release/zip_archives/android-arm-release/symbols.zip", + "out/ci/android_release/zip_archives/download.flutter.io" ], "realm": "production" } @@ -65,6 +67,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release", "--runtime-mode", "release", "--android", @@ -73,9 +77,9 @@ "--rbe", "--no-goma" ], - "name": "android_release", + "name": "ci/android_release", "ninja": { - "config": "android_release", + "config": "ci/android_release", "targets": [ "default", "clang_x64/gen_snapshot", @@ -87,15 +91,15 @@ { "archives": [ { - "name": "android_release_arm64", + "name": "ci/android_release_arm64", "type": "gcs", - "base_path": "out/android_release_arm64/zip_archives/", + "base_path": "out/ci/android_release_arm64/zip_archives/", "include_paths": [ - "out/android_release_arm64/zip_archives/android-arm64-release/artifacts.zip", - "out/android_release_arm64/zip_archives/android-arm64-release/linux-x64.zip", - "out/android_release_arm64/zip_archives/android-arm64-release/symbols.zip", - "out/android_release_arm64/zip_archives/android-arm64-release/analyze-snapshot-linux-x64.zip", - "out/android_release_arm64/zip_archives/download.flutter.io" + "out/ci/android_release_arm64/zip_archives/android-arm64-release/artifacts.zip", + "out/ci/android_release_arm64/zip_archives/android-arm64-release/linux-x64.zip", + "out/ci/android_release_arm64/zip_archives/android-arm64-release/symbols.zip", + "out/ci/android_release_arm64/zip_archives/android-arm64-release/analyze-snapshot-linux-x64.zip", + "out/ci/android_release_arm64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -108,6 +112,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release_arm64", "--runtime-mode", "release", "--android", @@ -116,9 +122,9 @@ "--rbe", "--no-goma" ], - "name": "android_release_arm64", + "name": "ci/android_release_arm64", "ninja": { - "config": "android_release_arm64", + "config": "ci/android_release_arm64", "targets": [ "default", "clang_x64/gen_snapshot", @@ -132,7 +138,7 @@ "language": "bash", "script": "flutter/ci/binary_size_treemap.sh", "parameters": [ - "../../src/out/android_release_arm64/libflutter.so", + "../../src/out/ci/android_release_arm64/libflutter.so", "${FLUTTER_LOGS_DIR}" ] } @@ -141,15 +147,15 @@ { "archives": [ { - "name": "android_profile_arm64", + "name": "ci/android_profile_arm64", "type": "gcs", - "base_path": "out/android_profile_arm64/zip_archives/", + "base_path": "out/ci/android_profile_arm64/zip_archives/", "include_paths": [ - "out/android_profile_arm64/zip_archives/android-arm64-profile/artifacts.zip", - "out/android_profile_arm64/zip_archives/android-arm64-profile/linux-x64.zip", - "out/android_profile_arm64/zip_archives/android-arm64-profile/symbols.zip", - "out/android_profile_arm64/zip_archives/android-arm64-profile/analyze-snapshot-linux-x64.zip", - "out/android_profile_arm64/zip_archives/download.flutter.io" + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/artifacts.zip", + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/linux-x64.zip", + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/symbols.zip", + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/analyze-snapshot-linux-x64.zip", + "out/ci/android_profile_arm64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -162,6 +168,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile_arm64", "--android", "--runtime-mode", "profile", @@ -170,9 +178,9 @@ "--rbe", "--no-goma" ], - "name": "android_profile_arm64", + "name": "ci/android_profile_arm64", "ninja": { - "config": "android_profile_arm64", + "config": "ci/android_profile_arm64", "targets": [ "clang_x64/gen_snapshot", "default", @@ -192,7 +200,7 @@ "script": "flutter/ci/firebase_testlab.py", "parameters": [ "--variant", - "android_profile_arm64" + "ci/android_profile_arm64" ], "test_if": "main" } @@ -201,15 +209,15 @@ { "archives": [ { - "name": "android_profile_x64", + "name": "ci/android_profile_x64", "type": "gcs", - "base_path": "out/android_profile_x64/zip_archives/", + "base_path": "out/ci/android_profile_x64/zip_archives/", "include_paths": [ - "out/android_profile_x64/zip_archives/android-x64-profile/artifacts.zip", - "out/android_profile_x64/zip_archives/android-x64-profile/linux-x64.zip", - "out/android_profile_x64/zip_archives/android-x64-profile/symbols.zip", - "out/android_profile_x64/zip_archives/android-x64-profile/analyze-snapshot-linux-x64.zip", - "out/android_profile_x64/zip_archives/download.flutter.io" + "out/ci/android_profile_x64/zip_archives/android-x64-profile/artifacts.zip", + "out/ci/android_profile_x64/zip_archives/android-x64-profile/linux-x64.zip", + "out/ci/android_profile_x64/zip_archives/android-x64-profile/symbols.zip", + "out/ci/android_profile_x64/zip_archives/android-x64-profile/analyze-snapshot-linux-x64.zip", + "out/ci/android_profile_x64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -222,6 +230,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile_x64", "--runtime-mode", "profile", "--android", @@ -230,9 +240,9 @@ "--rbe", "--no-goma" ], - "name": "android_profile_x64", + "name": "ci/android_profile_x64", "ninja": { - "config": "android_profile_x64", + "config": "ci/android_profile_x64", "targets": [ "default", "clang_x64/gen_snapshot", @@ -244,15 +254,15 @@ { "archives": [ { - "name": "android_release_x64", + "name": "ci/android_release_x64", "type": "gcs", - "base_path": "out/android_release_x64/zip_archives/", + "base_path": "out/ci/android_release_x64/zip_archives/", "include_paths": [ - "out/android_release_x64/zip_archives/android-x64-release/artifacts.zip", - "out/android_release_x64/zip_archives/android-x64-release/linux-x64.zip", - "out/android_release_x64/zip_archives/android-x64-release/symbols.zip", - "out/android_release_x64/zip_archives/android-x64-release/analyze-snapshot-linux-x64.zip", - "out/android_release_x64/zip_archives/download.flutter.io" + "out/ci/android_release_x64/zip_archives/android-x64-release/artifacts.zip", + "out/ci/android_release_x64/zip_archives/android-x64-release/linux-x64.zip", + "out/ci/android_release_x64/zip_archives/android-x64-release/symbols.zip", + "out/ci/android_release_x64/zip_archives/android-x64-release/analyze-snapshot-linux-x64.zip", + "out/ci/android_release_x64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -265,6 +275,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release_x64", "--runtime-mode", "release", "--android", @@ -273,9 +285,9 @@ "--rbe", "--no-goma" ], - "name": "android_release_x64", + "name": "ci/android_release_x64", "ninja": { - "config": "android_release_x64", + "config": "ci/android_release_x64", "targets": [ "default", "clang_x64/gen_snapshot", @@ -290,7 +302,8 @@ { "name": "Verify-export-symbols-release-binaries", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" diff --git a/ci/builders/linux_android_debug_engine.json b/ci/builders/linux_android_debug_engine.json index 1959f62b5cc20..c35c7fc59fc9b 100644 --- a/ci/builders/linux_android_debug_engine.json +++ b/ci/builders/linux_android_debug_engine.json @@ -3,12 +3,12 @@ { "archives": [ { - "name": "android_jit_release_x86", + "name": "ci/android_jit_release_x86", "type": "gcs", - "base_path": "out/android_jit_release_x86/zip_archives/", + "base_path": "out/ci/android_jit_release_x86/zip_archives/", "include_paths": [ - "out/android_jit_release_x86/zip_archives/android-x86-jit-release/artifacts.zip", - "out/android_jit_release_x86/zip_archives/download.flutter.io" + "out/ci/android_jit_release_x86/zip_archives/android-x86-jit-release/artifacts.zip", + "out/ci/android_jit_release_x86/zip_archives/download.flutter.io" ], "realm": "production" } @@ -21,15 +21,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_jit_release_x86", "--android", "--android-cpu=x86", "--runtime-mode=jit_release", "--rbe", "--no-goma" ], - "name": "android_jit_release_x86", + "name": "ci/android_jit_release_x86", "ninja": { - "config": "android_jit_release_x86", + "config": "ci/android_jit_release_x86", "targets": [ "flutter", "flutter/shell/platform/android:embedding_jars", @@ -44,12 +46,12 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "android_jit_release_x86", + "ci/android_jit_release_x86", "--type", "java", "--engine-capture-core-dump", "--android-variant", - "android_jit_release_x86" + "ci/android_jit_release_x86" ] } ] @@ -57,15 +59,15 @@ { "archives": [ { - "name": "android_debug", + "name": "ci/android_debug", "type": "gcs", - "base_path": "out/android_debug/zip_archives/", + "base_path": "out/ci/android_debug/zip_archives/", "include_paths": [ - "out/android_debug/zip_archives/android-arm/artifacts.zip", - "out/android_debug/zip_archives/android-arm/symbols.zip", - "out/android_debug/zip_archives/download.flutter.io", - "out/android_debug/zip_archives/sky_engine.zip", - "out/android_debug/zip_archives/android-javadoc.zip" + "out/ci/android_debug/zip_archives/android-arm/artifacts.zip", + "out/ci/android_debug/zip_archives/android-arm/symbols.zip", + "out/ci/android_debug/zip_archives/download.flutter.io", + "out/ci/android_debug/zip_archives/sky_engine.zip", + "out/ci/android_debug/zip_archives/android-javadoc.zip" ], "realm": "production" } @@ -78,15 +80,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug", "--android", "--android-cpu=arm", "--no-lto", "--rbe", "--no-goma" ], - "name": "android_debug", + "name": "ci/android_debug", "ninja": { - "config": "android_debug", + "config": "ci/android_debug", "targets": [ "flutter", "flutter/sky/dist:zip_old_location", @@ -102,12 +106,12 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "android_debug", + "ci/android_debug", "--type", "java", "--engine-capture-core-dump", "--android-variant", - "android_debug" + "ci/android_debug" ] } ] @@ -115,13 +119,13 @@ { "archives": [ { - "name": "android_debug_arm64", + "name": "ci/android_debug_arm64", "type": "gcs", - "base_path": "out/android_debug_arm64/zip_archives/", + "base_path": "out/ci/android_debug_arm64/zip_archives/", "include_paths": [ - "out/android_debug_arm64/zip_archives/android-arm64/artifacts.zip", - "out/android_debug_arm64/zip_archives/android-arm64/symbols.zip", - "out/android_debug_arm64/zip_archives/download.flutter.io" + "out/ci/android_debug_arm64/zip_archives/android-arm64/artifacts.zip", + "out/ci/android_debug_arm64/zip_archives/android-arm64/symbols.zip", + "out/ci/android_debug_arm64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -134,15 +138,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug_arm64", "--android", "--android-cpu=arm64", "--no-lto", "--rbe", "--no-goma" ], - "name": "android_debug_arm64", + "name": "ci/android_debug_arm64", "ninja": { - "config": "android_debug_arm64", + "config": "ci/android_debug_arm64", "targets": [ "flutter", "flutter/shell/platform/android:abi_jars" @@ -152,13 +158,13 @@ { "archives": [ { - "name": "android_debug_x86", + "name": "ci/android_debug_x86", "type": "gcs", - "base_path": "out/android_debug_x86/zip_archives/", + "base_path": "out/ci/android_debug_x86/zip_archives/", "include_paths": [ - "out/android_debug_x86/zip_archives/android-x86/artifacts.zip", - "out/android_debug_x86/zip_archives/android-x86/symbols.zip", - "out/android_debug_x86/zip_archives/download.flutter.io" + "out/ci/android_debug_x86/zip_archives/android-x86/artifacts.zip", + "out/ci/android_debug_x86/zip_archives/android-x86/symbols.zip", + "out/ci/android_debug_x86/zip_archives/download.flutter.io" ], "realm": "production" } @@ -171,15 +177,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug_x86", "--android", "--android-cpu=x86", "--no-lto", "--rbe", "--no-goma" ], - "name": "android_debug_x86", + "name": "ci/android_debug_x86", "ninja": { - "config": "android_debug_x86", + "config": "ci/android_debug_x86", "targets": [ "flutter", "flutter/shell/platform/android:abi_jars" @@ -189,13 +197,13 @@ { "archives": [ { - "name": "android_debug_x64", + "name": "ci/android_debug_x64", "type": "gcs", - "base_path": "out/android_debug_x64/zip_archives/", + "base_path": "out/ci/android_debug_x64/zip_archives/", "include_paths": [ - "out/android_debug_x64/zip_archives/android-x64/artifacts.zip", - "out/android_debug_x64/zip_archives/android-x64/symbols.zip", - "out/android_debug_x64/zip_archives/download.flutter.io" + "out/ci/android_debug_x64/zip_archives/android-x64/artifacts.zip", + "out/ci/android_debug_x64/zip_archives/android-x64/symbols.zip", + "out/ci/android_debug_x64/zip_archives/download.flutter.io" ], "realm": "production" } @@ -208,15 +216,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug_x64", "--android", "--android-cpu=x64", "--no-lto", "--rbe", "--no-goma" ], - "name": "android_debug_x64", + "name": "ci/android_debug_x64", "ninja": { - "config": "android_debug_x64", + "config": "ci/android_debug_x64", "targets": [ "flutter", "flutter/shell/platform/android:abi_jars" @@ -229,7 +239,8 @@ { "name": "Verify-export-symbols-release-binaries", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" diff --git a/ci/builders/linux_android_emulator.json b/ci/builders/linux_android_emulator.json index 4d5bb00957997..56e27025182a3 100644 --- a/ci/builders/linux_android_emulator.json +++ b/ci/builders/linux_android_emulator.json @@ -17,7 +17,7 @@ "--rbe", "--no-goma", "--target-dir", - "android_emulator_debug_x64" + "ci/android_emulator_debug_x64" ], "dependencies": [ { @@ -25,9 +25,9 @@ "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd" } ], - "name": "android_emulator_debug_x64", + "name": "ci/android_emulator_debug_x64", "ninja": { - "config": "android_emulator_debug_x64", + "config": "ci/android_emulator_debug_x64", "targets": [ "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", @@ -54,7 +54,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--android-variant", - "android_emulator_debug_x64", + "ci/android_emulator_debug_x64", "--type", "android" ] @@ -85,7 +85,7 @@ ], "script": "flutter/testing/scenario_app/bin/run_android_tests.dart", "parameters": [ - "--out-dir=../out/android_emulator_debug_x64", + "--out-dir=../out/ci/android_emulator_debug_x64", "--enable-impeller", "--impeller-backend=vulkan" ] @@ -109,7 +109,7 @@ "--rbe", "--no-goma", "--target-dir", - "android_emulator_debug_x86" + "ci/android_emulator_debug_x86" ], "dependencies": [ { @@ -117,9 +117,9 @@ "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd" } ], - "name": "android_emulator_debug_x86", + "name": "ci/android_emulator_debug_x86", "ninja": { - "config": "android_emulator_debug_x86", + "config": "ci/android_emulator_debug_x86", "targets": [ "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", @@ -146,7 +146,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--android-variant", - "android_emulator_debug_x86", + "ci/android_emulator_debug_x86", "--type", "android" ] diff --git a/ci/builders/linux_android_emulator_skia.json b/ci/builders/linux_android_emulator_skia.json index a1a4d0321b133..a711c8c71ea1b 100644 --- a/ci/builders/linux_android_emulator_skia.json +++ b/ci/builders/linux_android_emulator_skia.json @@ -17,7 +17,7 @@ "--rbe", "--no-goma", "--target-dir", - "android_emulator_skia_debug_x64" + "ci/android_emulator_skia_debug_x64" ], "dependencies": [ { @@ -25,9 +25,9 @@ "version": "git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd" } ], - "name": "android_emulator_skia_debug_x64", + "name": "ci/android_emulator_skia_debug_x64", "ninja": { - "config": "android_emulator_skia_debug_x64", + "config": "ci/android_emulator_skia_debug_x64", "targets": [ "flutter/impeller/toolkit/android:unittests", "flutter/shell/platform/android:flutter_shell_native_unittests", @@ -55,7 +55,7 @@ ], "script": "flutter/testing/scenario_app/bin/run_android_tests.dart", "parameters": [ - "--out-dir=../out/android_emulator_skia_debug_x64", + "--out-dir=../out/ci/android_emulator_skia_debug_x64", "--no-enable-impeller" ] }, @@ -79,7 +79,7 @@ ], "script": "flutter/testing/scenario_app/bin/run_android_tests.dart", "parameters": [ - "--out-dir=../out/android_emulator_skia_debug_x64", + "--out-dir=../out/ci/android_emulator_skia_debug_x64", "--no-enable-impeller", "--force-surface-producer-surface-texture" ] diff --git a/ci/builders/linux_arm_host_engine.json b/ci/builders/linux_arm_host_engine.json index a8a71846bfca8..937c6f57dfd62 100644 --- a/ci/builders/linux_arm_host_engine.json +++ b/ci/builders/linux_arm_host_engine.json @@ -3,11 +3,11 @@ { "archives": [ { - "name": "linux_profile_arm64", + "name": "ci/linux_profile_arm64", "type": "gcs", - "base_path": "out/linux_profile_arm64/zip_archives/", + "base_path": "out/ci/linux_profile_arm64/zip_archives/", "include_paths": [ - "out/linux_profile_arm64/zip_archives/linux-arm64-profile/linux-arm64-flutter-gtk.zip" + "out/ci/linux_profile_arm64/zip_archives/linux-arm64-profile/linux-arm64-flutter-gtk.zip" ], "realm": "production" } @@ -21,6 +21,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/linux_profile_arm64", "--runtime-mode", "profile", "--no-lto", @@ -30,9 +32,9 @@ "--rbe", "--no-goma" ], - "name": "linux_profile_arm64", + "name": "ci/linux_profile_arm64", "ninja": { - "config": "linux_profile_arm64", + "config": "ci/linux_profile_arm64", "targets": [ "flutter/shell/platform/linux:flutter_gtk" ] @@ -41,14 +43,14 @@ { "archives": [ { - "name": "linux_debug_arm64", + "name": "ci/linux_debug_arm64", "type": "gcs", - "base_path": "out/linux_debug_arm64/zip_archives/", + "base_path": "out/ci/linux_debug_arm64/zip_archives/", "include_paths": [ - "out/linux_debug_arm64/zip_archives/linux-arm64/artifacts.zip", - "out/linux_debug_arm64/zip_archives/linux-arm64/font-subset.zip", - "out/linux_debug_arm64/zip_archives/linux-arm64-debug/linux-arm64-flutter-gtk.zip", - "out/linux_debug_arm64/zip_archives/dart-sdk-linux-arm64.zip" + "out/ci/linux_debug_arm64/zip_archives/linux-arm64/artifacts.zip", + "out/ci/linux_debug_arm64/zip_archives/linux-arm64/font-subset.zip", + "out/ci/linux_debug_arm64/zip_archives/linux-arm64-debug/linux-arm64-flutter-gtk.zip", + "out/ci/linux_debug_arm64/zip_archives/dart-sdk-linux-arm64.zip" ], "realm": "production" } @@ -62,6 +64,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/linux_debug_arm64", "--runtime-mode", "debug", "--target-os=linux", @@ -70,9 +74,9 @@ "--rbe", "--no-goma" ], - "name": "linux_debug_arm64", + "name": "ci/linux_debug_arm64", "ninja": { - "config": "linux_debug_arm64", + "config": "ci/linux_debug_arm64", "targets": [ "flutter/build/archives:artifacts", "flutter/build/archives:dart_sdk_archive", @@ -84,11 +88,11 @@ { "archives": [ { - "name": "linux_release_arm64", + "name": "ci/linux_release_arm64", "type": "gcs", - "base_path": "out/linux_release_arm64/zip_archives/", + "base_path": "out/ci/linux_release_arm64/zip_archives/", "include_paths": [ - "out/linux_release_arm64/zip_archives/linux-arm64-release/linux-arm64-flutter-gtk.zip" + "out/ci/linux_release_arm64/zip_archives/linux-arm64-release/linux-arm64-flutter-gtk.zip" ], "realm": "production" } @@ -102,6 +106,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/linux_release_arm64", "--runtime-mode", "release", "--target-os=linux", @@ -110,9 +116,9 @@ "--rbe", "--no-goma" ], - "name": "linux_release_arm64", + "name": "ci/linux_release_arm64", "ninja": { - "config": "linux_release_arm64", + "config": "ci/linux_release_arm64", "targets": [ "flutter/shell/platform/linux:flutter_gtk" ] diff --git a/ci/builders/linux_clang_tidy.json b/ci/builders/linux_clang_tidy.json index cd546bc4d2ad0..0d81a7b8ac0c4 100644 --- a/ci/builders/linux_clang_tidy.json +++ b/ci/builders/linux_clang_tidy.json @@ -15,13 +15,13 @@ "arm64", "--no-lto", "--target-dir", - "android_debug_arm64_clang_tidy", + "ci/android_debug_arm64_clang_tidy", "--rbe", "--no-goma" ], - "name": "android_debug_arm64_clang_tidy", + "name": "ci/android_debug_arm64_clang_tidy", "ninja": { - "config": "android_debug_arm64_clang_tidy" + "config": "ci/android_debug_arm64_clang_tidy" } }, { @@ -39,13 +39,13 @@ "--prebuilt-dart-sdk", "--no-lto", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma" ], - "name": "host_debug_clang_tidy", + "name": "ci/host_debug_clang_tidy", "ninja": { - "config": "host_debug_clang_tidy" + "config": "ci/host_debug_clang_tidy" } } ], @@ -62,17 +62,17 @@ "download_android_deps": false }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "tasks": [ { "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=0", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -91,17 +91,17 @@ "download_android_deps": false }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "tasks": [ { "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=1", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -120,17 +120,17 @@ "download_android_deps": false }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "tasks": [ { "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=2", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -149,17 +149,17 @@ "download_android_deps": false }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "tasks": [ { "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=3", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -175,18 +175,18 @@ "cores=32" ], "dependencies": [ - "host_debug_clang_tidy", - "android_debug_arm64_clang_tidy" + "ci/host_debug_clang_tidy", + "ci/android_debug_arm64_clang_tidy" ], "tasks": [ { "name": "test: lint android_debug_arm64", "parameters": [ "--variant", - "android_debug_arm64_clang_tidy", + "ci/android_debug_arm64_clang_tidy", "--lint-all", "--shard-id=0", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" diff --git a/ci/builders/linux_fuchsia.json b/ci/builders/linux_fuchsia.json index ab96dfc260229..6212ee2b5ed02 100644 --- a/ci/builders/linux_fuchsia.json +++ b/ci/builders/linux_fuchsia.json @@ -10,6 +10,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_profile_arm64", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -18,9 +20,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_profile_arm64", + "name": "ci/fuchsia_profile_arm64", "ninja": { - "config": "fuchsia_profile_arm64", + "config": "ci/fuchsia_profile_arm64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -39,6 +41,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_profile_arm64_tester", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -48,9 +52,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_profile_arm64_tester", + "name": "ci/fuchsia_profile_arm64_tester", "ninja": { - "config": "fuchsia_profile_arm64", + "config": "ci/fuchsia_profile_arm64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -64,7 +68,7 @@ "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ "testing/fuchsia/run_tests.py", - "fuchsia_profile_arm64" + "ci/fuchsia_profile_arm64_tester" ] } ] @@ -79,6 +83,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_release_arm64", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -87,9 +93,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_release_arm64", + "name": "ci/fuchsia_release_arm64", "ninja": { - "config": "fuchsia_release_arm64", + "config": "ci/fuchsia_release_arm64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -108,6 +114,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_release_arm64_tester", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -117,9 +125,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_release_arm64_tester", + "name": "ci/fuchsia_release_arm64_tester", "ninja": { - "config": "fuchsia_release_arm64", + "config": "ci/fuchsia_release_arm64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -133,7 +141,7 @@ "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ "testing/fuchsia/run_tests.py", - "fuchsia_release_arm64" + "ci/fuchsia_release_arm64_tester" ] } ] @@ -148,6 +156,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_debug_arm64", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -157,9 +167,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_debug_arm64", + "name": "ci/fuchsia_debug_arm64", "ninja": { - "config": "fuchsia_debug_arm64", + "config": "ci/fuchsia_debug_arm64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -172,7 +182,7 @@ "script": "flutter/tools/fuchsia/upload_to_symbol_server.py", "parameters": [ "--symbol-dir", - "out/fuchsia_debug_arm64/.build-id", + "out/ci/fuchsia_debug_arm64/.build-id", "--engine-version", "${REVISION}", "--upload" @@ -193,6 +203,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_debug_arm64_tester", "--fuchsia", "--fuchsia-cpu", "arm64", @@ -202,9 +214,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_debug_arm64_tester", + "name": "ci/fuchsia_debug_arm64_tester", "ninja": { - "config": "fuchsia_debug_arm64", + "config": "ci/fuchsia_debug_arm64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -218,7 +230,7 @@ "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ "testing/fuchsia/run_tests.py", - "fuchsia_debug_arm64" + "ci/fuchsia_debug_arm64_tester" ] } ] @@ -233,6 +245,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_profile_x64", "--fuchsia", "--fuchsia-cpu", "x64", @@ -241,9 +255,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_profile_x64", + "name": "ci/fuchsia_profile_x64", "ninja": { - "config": "fuchsia_profile_x64", + "config": "ci/fuchsia_profile_x64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -262,6 +276,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_profile_x64_tester", "--fuchsia", "--fuchsia-cpu", "x64", @@ -271,9 +287,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_profile_x64_tester", + "name": "ci/fuchsia_profile_x64_tester", "ninja": { - "config": "fuchsia_profile_x64", + "config": "ci/fuchsia_profile_x64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -287,7 +303,7 @@ "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ "testing/fuchsia/run_tests.py", - "fuchsia_profile_x64" + "ci/fuchsia_profile_x64_tester" ] } ] @@ -303,6 +319,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_release_x64", "--fuchsia", "--fuchsia-cpu", "x64", @@ -311,9 +329,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_release_x64", + "name": "ci/fuchsia_release_x64", "ninja": { - "config": "fuchsia_release_x64", + "config": "ci/fuchsia_release_x64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -332,6 +350,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_release_x64_tester", "--fuchsia", "--fuchsia-cpu", "x64", @@ -341,9 +361,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_release_x64_tester", + "name": "ci/fuchsia_release_x64_tester", "ninja": { - "config": "fuchsia_release_x64", + "config": "ci/fuchsia_release_x64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -357,7 +377,7 @@ "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ "testing/fuchsia/run_tests.py", - "fuchsia_release_x64" + "ci/fuchsia_release_x64_tester" ] } ] @@ -373,6 +393,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_debug_x64", "--fuchsia", "--fuchsia-cpu", "x64", @@ -382,9 +404,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_debug_x64", + "name": "ci/fuchsia_debug_x64", "ninja": { - "config": "fuchsia_debug_x64", + "config": "ci/fuchsia_debug_x64", "targets": [ "flutter/shell/platform/fuchsia:fuchsia" ] @@ -397,7 +419,7 @@ "script": "flutter/tools/fuchsia/upload_to_symbol_server.py", "parameters": [ "--symbol-dir", - "out/fuchsia_debug_x64/.build-id", + "out/ci/fuchsia_debug_x64/.build-id", "--engine-version", "${REVISION}", "--upload" @@ -418,6 +440,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/fuchsia_debug_x64_tester", "--fuchsia", "--fuchsia-cpu", "x64", @@ -427,9 +451,9 @@ "--rbe", "--no-goma" ], - "name": "fuchsia_debug_x64_tester", + "name": "ci/fuchsia_debug_x64_tester", "ninja": { - "config": "fuchsia_debug_x64", + "config": "ci/fuchsia_debug_x64_tester", "targets": [ "flutter/shell/platform/fuchsia:fuchsia", "flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests", @@ -450,7 +474,8 @@ "language": "python3", "script": "flutter/tools/fuchsia/with_envs.py", "parameters": [ - "testing/fuchsia/run_tests.py" + "testing/fuchsia/run_tests.py", + "ci/fuchsia_debug_x64_tester" ] } ] @@ -480,9 +505,9 @@ "--out-dir", "${LUCI_CLEANUP}", "--symbol-dirs", - "out/fuchsia_debug_arm64/.build-id", - "out/fuchsia_profile_arm64/.build-id", - "out/fuchsia_release_arm64/.build-id" + "out/ci/fuchsia_debug_arm64/.build-id", + "out/ci/fuchsia_profile_arm64/.build-id", + "out/ci/fuchsia_release_arm64/.build-id" ], "script": "flutter/tools/fuchsia/merge_and_upload_debug_symbols.py", "language": "python3" @@ -498,9 +523,9 @@ "--out-dir", "${LUCI_CLEANUP}", "--symbol-dirs", - "out/fuchsia_debug_x64/.build-id", - "out/fuchsia_profile_x64/.build-id", - "out/fuchsia_release_x64/.build-id" + "out/ci/fuchsia_debug_x64/.build-id", + "out/ci/fuchsia_profile_x64/.build-id", + "out/ci/fuchsia_release_x64/.build-id" ], "script": "flutter/tools/fuchsia/merge_and_upload_debug_symbols.py", "language": "python3" @@ -508,7 +533,8 @@ { "name": "Verify-export-symbols-release-binaries", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" diff --git a/ci/builders/linux_host_desktop_engine.json b/ci/builders/linux_host_desktop_engine.json index 29393e3a6b976..773deb9b26a8d 100644 --- a/ci/builders/linux_host_desktop_engine.json +++ b/ci/builders/linux_host_desktop_engine.json @@ -3,11 +3,11 @@ { "archives": [ { - "name": "host_debug", - "base_path": "out/host_debug_desktop/zip_archives/", + "name": "ci/host_debug_desktop", + "base_path": "out/ci/host_debug_desktop/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_debug_desktop/zip_archives/linux-x64-debug/linux-x64-flutter-gtk.zip" + "out/ci/host_debug_desktop/zip_archives/linux-x64-debug/linux-x64-flutter-gtk.zip" ], "realm": "production" } @@ -28,11 +28,11 @@ "--rbe", "--no-goma", "--target-dir", - "host_debug_desktop" + "ci/host_debug_desktop" ], - "name": "host_debug_desktop", + "name": "ci/host_debug_desktop", "ninja": { - "config": "host_debug_desktop", + "config": "ci/host_debug_desktop", "targets": [ "flutter/shell/platform/linux:flutter_gtk" ] @@ -41,11 +41,11 @@ { "archives": [ { - "name": "host_profile", - "base_path": "out/host_profile_desktop/zip_archives/", + "name": "ci/host_profile_desktop", + "base_path": "out/ci/host_profile_desktop/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_profile_desktop/zip_archives/linux-x64-profile/linux-x64-flutter-gtk.zip" + "out/ci/host_profile_desktop/zip_archives/linux-x64-profile/linux-x64-flutter-gtk.zip" ], "realm": "production" } @@ -67,11 +67,11 @@ "--rbe", "--no-goma", "--target-dir", - "host_profile_desktop" + "ci/host_profile_desktop" ], - "name": "host_profile_desktop", + "name": "ci/host_profile_desktop", "ninja": { - "config": "host_profile_desktop", + "config": "ci/host_profile_desktop", "targets": [ "flutter/shell/platform/linux:flutter_gtk" ] @@ -80,11 +80,11 @@ { "archives": [ { - "name": "host_release", - "base_path": "out/host_release_desktop/zip_archives/", + "name": "ci/host_release_desktop", + "base_path": "out/ci/host_release_desktop/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_release_desktop/zip_archives/linux-x64-release/linux-x64-flutter-gtk.zip" + "out/ci/host_release_desktop/zip_archives/linux-x64-release/linux-x64-flutter-gtk.zip" ], "realm": "production" } @@ -105,11 +105,11 @@ "--rbe", "--no-goma", "--target-dir", - "host_release_desktop" + "ci/host_release_desktop" ], - "name": "host_release_desktop", + "name": "ci/host_release_desktop", "ninja": { - "config": "host_release_desktop", + "config": "ci/host_release_desktop", "targets": [ "flutter/shell/platform/linux:flutter_gtk" ] diff --git a/ci/builders/linux_host_engine.json b/ci/builders/linux_host_engine.json index a9e14038fc590..904dbaa3b8b42 100644 --- a/ci/builders/linux_host_engine.json +++ b/ci/builders/linux_host_engine.json @@ -3,15 +3,15 @@ { "archives": [ { - "name": "host_debug", - "base_path": "out/host_debug/zip_archives/", + "name": "ci/host_debug", + "base_path": "out/ci/host_debug/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_debug/zip_archives/linux-x64/artifacts.zip", - "out/host_debug/zip_archives/linux-x64/linux-x64-embedder.zip", - "out/host_debug/zip_archives/linux-x64/font-subset.zip", - "out/host_debug/zip_archives/flutter_patched_sdk.zip", - "out/host_debug/zip_archives/dart-sdk-linux-x64.zip" + "out/ci/host_debug/zip_archives/linux-x64/artifacts.zip", + "out/ci/host_debug/zip_archives/linux-x64/linux-x64-embedder.zip", + "out/ci/host_debug/zip_archives/linux-x64/font-subset.zip", + "out/ci/host_debug/zip_archives/flutter_patched_sdk.zip", + "out/ci/host_debug/zip_archives/dart-sdk-linux-x64.zip" ], "realm": "production" } @@ -25,6 +25,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_debug", "--runtime-mode", "debug", "--prebuilt-dart-sdk", @@ -32,9 +34,9 @@ "--rbe", "--no-goma" ], - "name": "host_debug", + "name": "ci/host_debug", "ninja": { - "config": "host_debug", + "config": "ci/host_debug", "targets": [ "flutter:unittests", "flutter/build/archives:artifacts", @@ -52,7 +54,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug", + "ci/host_debug", "--type", "dart,dart-host", "--engine-capture-core-dump" @@ -63,8 +65,8 @@ { "archives": [ { - "name": "host_profile", - "base_path": "out/host_profile/zip_archives/", + "name": "ci/host_profile", + "base_path": "out/ci/host_profile/zip_archives/", "type": "gcs", "include_paths": [] } @@ -78,6 +80,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_profile", "--runtime-mode", "profile", "--no-lto", @@ -86,9 +90,9 @@ "--rbe", "--no-goma" ], - "name": "host_profile", + "name": "ci/host_profile", "ninja": { - "config": "host_profile", + "config": "ci/host_profile", "targets": [ "flutter/build/dart:copy_dart_sdk", "flutter/shell/testing", @@ -103,7 +107,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_profile", + "ci/host_profile", "--type", "dart,dart-host,engine", "--engine-capture-core-dump" @@ -114,11 +118,11 @@ { "archives": [ { - "name": "host_release", - "base_path": "out/host_release/zip_archives/", + "name": "ci/host_release", + "base_path": "out/ci/host_release/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_release/zip_archives/flutter_patched_sdk_product.zip" + "out/ci/host_release/zip_archives/flutter_patched_sdk_product.zip" ], "realm": "production" } @@ -138,6 +142,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_release", "--runtime-mode", "release", "--prebuilt-dart-sdk", @@ -145,9 +151,9 @@ "--rbe", "--no-goma" ], - "name": "host_release", + "name": "ci/host_release", "ninja": { - "config": "host_release", + "config": "ci/host_release", "targets": [ "flutter/build/dart:copy_dart_sdk", "flutter/display_list:display_list_benchmarks", @@ -173,7 +179,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_release", + "ci/host_release", "--type", "dart,dart-host,engine,benchmarks", "--engine-capture-core-dump" @@ -182,13 +188,17 @@ { "language": "bash", "name": "Generate metrics test", - "script": "flutter/testing/benchmark/generate_metrics.sh" + "script": "flutter/testing/benchmark/generate_metrics.sh", + "parameters": [ + "ci/host_release" + ] }, { "language": "bash", "name": "Upload metrics dry-run", "script": "flutter/testing/benchmark/upload_metrics.sh", "parameters": [ + "ci/host_release", "--no-upload" ] } @@ -200,7 +210,8 @@ { "name": "Verify-export-symbols-release-binaries", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" diff --git a/ci/builders/linux_unopt.json b/ci/builders/linux_unopt.json index 4987afb3773ab..d80b870c944a0 100644 --- a/ci/builders/linux_unopt.json +++ b/ci/builders/linux_unopt.json @@ -10,6 +10,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_debug_unopt", "--runtime-mode", "debug", "--unoptimized", @@ -20,9 +22,9 @@ "--rbe", "--no-goma" ], - "name": "host_debug_unopt", + "name": "ci/host_debug_unopt", "ninja": { - "config": "host_debug_unopt", + "config": "ci/host_debug_unopt", "targets": [ "flutter/tools/font_subset", "flutter:unittests", @@ -62,7 +64,7 @@ "--logs-dir", "${FLUTTER_LOGS_DIR}", "--variant", - "host_debug_unopt", + "ci/host_debug_unopt", "--type", "dart,dart-host,engine", "--engine-capture-core-dump", @@ -82,7 +84,7 @@ "name": "test: observatory and service protocol", "script": "flutter/shell/testing/observatory/test.dart", "parameters": [ - "out/host_debug_unopt/flutter_tester", + "out/ci/host_debug_unopt/flutter_tester", "flutter/shell/testing/observatory/empty_main.dart" ] }, @@ -119,14 +121,14 @@ "--unoptimized", "--prebuilt-dart-sdk", "--target-dir", - "host_debug_unopt_impeller_tests", + "ci/host_debug_unopt_impeller_tests", "--rbe", "--no-goma", "--use-glfw-swiftshader" ], - "name": "host_debug_unopt_impeller_tests", + "name": "ci/host_debug_unopt_impeller_tests", "ninja": { - "config": "host_debug_unopt_impeller_tests", + "config": "ci/host_debug_unopt_impeller_tests", "targets": [ "flutter", "flutter/sky/packages" @@ -139,7 +141,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug_unopt_impeller_tests", + "ci/host_debug_unopt_impeller_tests", "--type", "impeller", "--engine-capture-core-dump" @@ -161,14 +163,14 @@ "--android", "--embedder-for-target", "--target-dir", - "android_embedder_debug_unopt", + "ci/android_embedder_debug_unopt", "--unoptimized", "--rbe", "--no-goma" ], - "name": "android_embedder_debug_unopt", + "name": "ci/android_embedder_debug_unopt", "ninja": { - "config": "android_embedder_debug_unopt", + "config": "ci/android_embedder_debug_unopt", "targets": [ "flutter/shell/platform/embedder:flutter_engine" ] @@ -184,6 +186,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug_arm64_validation_layers", "--android", "--android-cpu=arm64", "--no-lto", @@ -191,9 +195,9 @@ "--rbe", "--no-goma" ], - "name": "android_debug_arm64_validation_layers", + "name": "ci/android_debug_arm64_validation_layers", "ninja": { - "config": "android_debug_arm64", + "config": "ci/android_debug_arm64_validation_layers", "targets": [ "flutter", "flutter/shell/platform/android:abi_jars" @@ -215,14 +219,16 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_debug_unopt", "--android", "--unoptimized", "--rbe", "--no-goma" ], - "name": "android_debug_unopt", + "name": "ci/android_debug_unopt", "ninja": { - "config": "android_debug_unopt", + "config": "ci/android_debug_unopt", "targets": [ "flutter/impeller", "flutter/shell/platform/android:android_jar", @@ -236,12 +242,12 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "android_debug_unopt", + "ci/android_debug_unopt", "--type", "java", "--engine-capture-core-dump", "--android-variant", - "android_debug_unopt" + "ci/android_debug_unopt" ] }, { @@ -252,7 +258,7 @@ "--before-relative-to-src", "flutter/impeller/tools/malioc.json", "--after-relative-to-src", - "out/android_debug_unopt/gen/malioc", + "out/ci/android_debug_unopt/gen/malioc", "--print-diff" ] } diff --git a/ci/builders/linux_unopt_debug_no_rbe.json b/ci/builders/linux_unopt_debug_no_rbe.json index 38ee6cbd60cb8..f9c200917f429 100644 --- a/ci/builders/linux_unopt_debug_no_rbe.json +++ b/ci/builders/linux_unopt_debug_no_rbe.json @@ -19,11 +19,11 @@ "--no-rbe", "--no-goma", "--target-dir", - "linux_unopt_debug_no_rbe" + "ci/linux_unopt_debug_no_rbe" ], - "name": "linux_unopt_debug_no_rbe", + "name": "ci/linux_unopt_debug_no_rbe", "ninja": { - "config": "linux_unopt_debug_no_rbe", + "config": "ci/linux_unopt_debug_no_rbe", "targets": ["flutter/tools/font_subset"] }, "tests": [ @@ -31,7 +31,10 @@ "language": "dart", "name": "clangd", "script": "flutter/tools/clangd_check/bin/main.dart", - "parameters": ["--clangd=buildtools/linux-x64/clang/bin/clangd"] + "parameters": [ + "--clangd=buildtools/linux-x64/clang/bin/clangd", + "--compile-commands-dir=../out/ci/linux_unopt_debug_no_rbe" + ] } ] } diff --git a/ci/builders/mac_android_aot_engine.json b/ci/builders/mac_android_aot_engine.json index b6889f57efdfe..58463ae05d00c 100644 --- a/ci/builders/mac_android_aot_engine.json +++ b/ci/builders/mac_android_aot_engine.json @@ -3,12 +3,12 @@ { "archives": [ { - "base_path": "out/android_profile/zip_archives/", + "base_path": "out/ci/android_profile/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile/zip_archives/android-arm-profile/darwin-x64.zip" + "out/ci/android_profile/zip_archives/android-arm-profile/darwin-x64.zip" ], - "name": "android_profile", + "name": "ci/android_profile", "realm": "production" } ], @@ -21,13 +21,15 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_profile", "--runtime-mode", "profile", "--android" ], - "name": "android_profile", + "name": "ci/android_profile", "ninja": { - "config": "android_profile", + "config": "ci/android_profile", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" @@ -42,12 +44,12 @@ { "archives": [ { - "base_path": "out/android_profile_arm64/zip_archives/", + "base_path": "out/ci/android_profile_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile_arm64/zip_archives/android-arm64-profile/darwin-x64.zip" + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/darwin-x64.zip" ], - "name": "android_profile_arm64", + "name": "ci/android_profile_arm64", "realm": "production" } ], @@ -60,14 +62,16 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_profile_arm64", "--runtime-mode", "profile", "--android", "--android-cpu=arm64" ], - "name": "android_profile_arm64", + "name": "ci/android_profile_arm64", "ninja": { - "config": "android_profile_arm64", + "config": "ci/android_profile_arm64", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" @@ -82,12 +86,12 @@ { "archives": [ { - "base_path": "out/android_profile_x64/zip_archives/", + "base_path": "out/ci/android_profile_x64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile_x64/zip_archives/android-x64-profile/darwin-x64.zip" + "out/ci/android_profile_x64/zip_archives/android-x64-profile/darwin-x64.zip" ], - "name": "android_profile_x64", + "name": "ci/android_profile_x64", "realm": "production" } ], @@ -100,14 +104,16 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_profile_x64", "--runtime-mode", "profile", "--android", "--android-cpu=x64" ], - "name": "android_profile_x64", + "name": "ci/android_profile_x64", "ninja": { - "config": "android_profile_x64", + "config": "ci/android_profile_x64", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" @@ -122,12 +128,12 @@ { "archives": [ { - "base_path": "out/android_release/zip_archives/", + "base_path": "out/ci/android_release/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release/zip_archives/android-arm-release/darwin-x64.zip" + "out/ci/android_release/zip_archives/android-arm-release/darwin-x64.zip" ], - "name": "android_release", + "name": "ci/android_release", "realm": "production" } ], @@ -140,13 +146,15 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_release", "--runtime-mode", "release", "--android" ], - "name": "android_release", + "name": "ci/android_release", "ninja": { - "config": "android_release", + "config": "ci/android_release", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" @@ -161,12 +169,12 @@ { "archives": [ { - "base_path": "out/android_release_arm64/zip_archives/", + "base_path": "out/ci/android_release_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release_arm64/zip_archives/android-arm64-release/darwin-x64.zip" + "out/ci/android_release_arm64/zip_archives/android-arm64-release/darwin-x64.zip" ], - "name": "android_release_arm64", + "name": "ci/android_release_arm64", "realm": "production" } ], @@ -179,14 +187,16 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_release_arm64", "--runtime-mode", "release", "--android", "--android-cpu=arm64" ], - "name": "android_release_arm64", + "name": "ci/android_release_arm64", "ninja": { - "config": "android_release_arm64", + "config": "ci/android_release_arm64", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" @@ -201,12 +211,12 @@ { "archives": [ { - "base_path": "out/android_release_x64/zip_archives/", + "base_path": "out/ci/android_release_x64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release_x64/zip_archives/android-x64-release/darwin-x64.zip" + "out/ci/android_release_x64/zip_archives/android-x64-release/darwin-x64.zip" ], - "name": "android_release_x64", + "name": "ci/android_release_x64", "realm": "production" } ], @@ -219,14 +229,16 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/android_release_x64", "--runtime-mode", "release", "--android", "--android-cpu=x64" ], - "name": "android_release_x64", + "name": "ci/android_release_x64", "ninja": { - "config": "android_release_x64", + "config": "ci/android_release_x64", "targets": [ "flutter/lib/snapshot", "flutter/shell/platform/android:gen_snapshot" diff --git a/ci/builders/mac_clang_tidy.json b/ci/builders/mac_clang_tidy.json index 6f50c27f0e350..789ee39feabbb 100644 --- a/ci/builders/mac_clang_tidy.json +++ b/ci/builders/mac_clang_tidy.json @@ -17,14 +17,14 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" ], - "name": "host_debug_clang_tidy", + "name": "ci/host_debug_clang_tidy", "ninja": { - "config": "host_debug_clang_tidy" + "config": "ci/host_debug_clang_tidy" } }, { @@ -45,14 +45,14 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "ios_debug_sim_clang_tidy", + "ci/ios_debug_sim_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" ], - "name": "ios_debug_sim_clang_tidy", + "name": "ci/ios_debug_sim_clang_tidy", "ninja": { - "config": "ios_debug_sim_clang_tidy" + "config": "ci/ios_debug_sim_clang_tidy" } } ], @@ -70,7 +70,7 @@ "use_rbe": true }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "contexts": [ "osx_sdk" @@ -87,7 +87,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -97,10 +97,10 @@ "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=0", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -120,7 +120,7 @@ "use_rbe": true }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "contexts": [ "osx_sdk" @@ -137,7 +137,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -147,10 +147,10 @@ "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=1", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -170,7 +170,7 @@ "use_rbe": true }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "contexts": [ "osx_sdk" @@ -187,7 +187,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -197,10 +197,10 @@ "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=2", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -220,7 +220,7 @@ "use_rbe": true }, "dependencies": [ - "host_debug_clang_tidy" + "ci/host_debug_clang_tidy" ], "contexts": [ "osx_sdk" @@ -237,7 +237,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -247,10 +247,10 @@ "name": "test: lint host_debug", "parameters": [ "--variant", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--lint-all", "--shard-id=3", - "--shard-variants=host_debug_clang_tidy,host_debug_clang_tidy,host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy,ci/host_debug_clang_tidy,ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" @@ -270,8 +270,8 @@ "use_rbe": true }, "dependencies": [ - "host_debug_clang_tidy", - "ios_debug_sim_clang_tidy" + "ci/host_debug_clang_tidy", + "ci/ios_debug_sim_clang_tidy" ], "contexts": [ "osx_sdk" @@ -288,7 +288,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "host_debug_clang_tidy", + "ci/host_debug_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -306,7 +306,7 @@ "--no-lto", "--force-mac-arm64", "--target-dir", - "ios_debug_sim_clang_tidy", + "ci/ios_debug_sim_clang_tidy", "--rbe", "--no-goma", "--xcode-symlinks" @@ -316,10 +316,10 @@ "name": "test: lint ios_debug_sim", "parameters": [ "--variant", - "ios_debug_sim_clang_tidy", + "ci/ios_debug_sim_clang_tidy", "--lint-all", "--shard-id=0", - "--shard-variants=host_debug_clang_tidy" + "--shard-variants=ci/host_debug_clang_tidy" ], "max_attempts": 1, "script": "flutter/ci/clang_tidy.sh" diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index c12a0632a134d..7d116dd65e54b 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -3,13 +3,13 @@ { "archives": [ { - "base_path": "out/host_debug/zip_archives/", + "base_path": "out/ci/host_debug/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_debug/zip_archives/darwin-x64/artifacts.zip", - "out/host_debug/zip_archives/dart-sdk-darwin-x64.zip" + "out/ci/host_debug/zip_archives/darwin-x64/artifacts.zip", + "out/ci/host_debug/zip_archives/dart-sdk-darwin-x64.zip" ], - "name": "host_debug", + "name": "ci/host_debug", "realm": "production" } ], @@ -23,6 +23,8 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/host_debug", "--runtime-mode", "debug", "--no-lto", @@ -30,9 +32,9 @@ "--build-embedder-examples", "--use-glfw-swiftshader" ], - "name": "host_debug", + "name": "ci/host_debug", "ninja": { - "config": "host_debug", + "config": "ci/host_debug", "targets": [ "flutter/build/archives:archive_gen_snapshot", "flutter/build/archives:artifacts", @@ -56,7 +58,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug", + "ci/host_debug", "--type", "dart,dart-host,engine", "--engine-capture-core-dump" @@ -67,12 +69,12 @@ { "archives": [ { - "base_path": "out/host_profile/zip_archives/", + "base_path": "out/ci/host_profile/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_profile/zip_archives/darwin-x64-profile/artifacts.zip" + "out/ci/host_profile/zip_archives/darwin-x64-profile/artifacts.zip" ], - "name": "host_profile", + "name": "ci/host_profile", "realm": "production" } ], @@ -86,15 +88,17 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/host_profile", "--runtime-mode", "profile", "--no-lto", "--prebuilt-dart-sdk", "--build-embedder-examples" ], - "name": "host_profile", + "name": "ci/host_profile", "ninja": { - "config": "host_profile", + "config": "ci/host_profile", "targets": [ "flutter/build/dart:copy_dart_sdk", "flutter/build/archives:archive_gen_snapshot", @@ -115,7 +119,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_profile", + "ci/host_profile", "--type", "dart,dart-host,engine", "--engine-capture-core-dump" @@ -126,13 +130,13 @@ { "archives": [ { - "base_path": "out/host_release/zip_archives/", + "base_path": "out/ci/host_release/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_release/zip_archives/darwin-x64-release/artifacts.zip", - "out/host_release/zip_archives/darwin-x64/font-subset.zip" + "out/ci/host_release/zip_archives/darwin-x64-release/artifacts.zip", + "out/ci/host_release/zip_archives/darwin-x64/font-subset.zip" ], - "name": "host_release", + "name": "ci/host_release", "realm": "production" } ], @@ -152,6 +156,8 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/host_release", "--runtime-mode", "release", "--no-lto", @@ -159,9 +165,9 @@ "--build-embedder-examples", "--use-glfw-swiftshader" ], - "name": "host_release", + "name": "ci/host_release", "ninja": { - "config": "host_release", + "config": "ci/host_release", "targets": [ "flutter/build/archives:archive_gen_snapshot", "flutter/build/archives:artifacts", @@ -184,7 +190,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_release", + "ci/host_release", "--type", "dart,dart-host,engine,impeller-golden" ] @@ -194,13 +200,13 @@ { "archives": [ { - "base_path": "out/mac_debug_arm64/zip_archives/", + "base_path": "out/ci/mac_debug_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/mac_debug_arm64/zip_archives/darwin-arm64/artifacts.zip", - "out/mac_debug_arm64/zip_archives/dart-sdk-darwin-arm64.zip" + "out/ci/mac_debug_arm64/zip_archives/darwin-arm64/artifacts.zip", + "out/ci/mac_debug_arm64/zip_archives/dart-sdk-darwin-arm64.zip" ], - "name": "mac_debug_arm64", + "name": "ci/mac_debug_arm64", "realm": "production" } ], @@ -213,6 +219,8 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/mac_debug_arm64", "--mac", "--mac-cpu", "arm64", @@ -221,9 +229,9 @@ "--no-lto", "--prebuilt-dart-sdk" ], - "name": "mac_debug_arm64", + "name": "ci/mac_debug_arm64", "ninja": { - "config": "mac_debug_arm64", + "config": "ci/mac_debug_arm64", "targets": [ "flutter/tools/font_subset", "flutter/build/archives:archive_gen_snapshot", @@ -242,12 +250,12 @@ { "archives": [ { - "base_path": "out/mac_profile_arm64/zip_archives/", + "base_path": "out/ci/mac_profile_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/mac_profile_arm64/zip_archives/darwin-arm64-profile/artifacts.zip" + "out/ci/mac_profile_arm64/zip_archives/darwin-arm64-profile/artifacts.zip" ], - "name": "mac_profile_arm64", + "name": "ci/mac_profile_arm64", "realm": "production" } ], @@ -260,6 +268,8 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/mac_profile_arm64", "--mac", "--mac-cpu", "arm64", @@ -268,9 +278,9 @@ "--no-lto", "--prebuilt-dart-sdk" ], - "name": "mac_profile_arm64", + "name": "ci/mac_profile_arm64", "ninja": { - "config": "mac_profile_arm64", + "config": "ci/mac_profile_arm64", "targets": [ "flutter/build/archives:artifacts", "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" @@ -285,11 +295,11 @@ { "archives": [ { - "base_path": "out/mac_release_arm64/zip_archives/", + "base_path": "out/ci/mac_release_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/mac_release_arm64/zip_archives/darwin-arm64/font-subset.zip", - "out/mac_release_arm64/zip_archives/darwin-arm64-release/artifacts.zip" + "out/ci/mac_release_arm64/zip_archives/darwin-arm64/font-subset.zip", + "out/ci/mac_release_arm64/zip_archives/darwin-arm64-release/artifacts.zip" ], "name": "mac_release_arm64", "realm": "production" @@ -304,6 +314,8 @@ "download_android_deps": false }, "gn": [ + "--target-dir", + "ci/mac_release_arm64", "--mac", "--mac-cpu", "arm64", @@ -312,9 +324,9 @@ "--no-lto", "--prebuilt-dart-sdk" ], - "name": "mac_release_arm64", + "name": "ci/mac_release_arm64", "ninja": { - "config": "mac_release_arm64", + "config": "ci/mac_release_arm64", "targets": [ "flutter/tools/font_subset", "flutter/build/archives:artifacts", @@ -336,9 +348,9 @@ "--dst", "out/debug/framework", "--arm64-out-dir", - "out/mac_debug_arm64", + "out/ci/mac_debug_arm64", "--x64-out-dir", - "out/host_debug", + "out/ci/host_debug", "--zip" ], "script": "flutter/sky/tools/create_embedder_framework.py" @@ -349,9 +361,9 @@ "--dst", "out/release/framework", "--arm64-out-dir", - "out/mac_release_arm64", + "out/ci/mac_release_arm64", "--x64-out-dir", - "out/host_release", + "out/ci/host_release", "--dsym", "--strip", "--zip" @@ -364,9 +376,9 @@ "--dst", "out/debug/framework", "--arm64-out-dir", - "out/mac_debug_arm64", + "out/ci/mac_debug_arm64", "--x64-out-dir", - "out/host_debug", + "out/ci/host_debug", "--zip" ], "script": "flutter/sky/tools/create_macos_framework.py" @@ -377,9 +389,9 @@ "--dst", "out/profile/framework", "--arm64-out-dir", - "out/mac_profile_arm64", + "out/ci/mac_profile_arm64", "--x64-out-dir", - "out/host_profile", + "out/ci/host_profile", "--zip" ], "script": "flutter/sky/tools/create_macos_framework.py" @@ -387,7 +399,8 @@ { "name": "Verify-export-symbols", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" @@ -398,9 +411,9 @@ "--dst", "out/debug/snapshot", "--arm64-out-dir", - "out/mac_debug_arm64", + "out/ci/mac_debug_arm64", "--x64-out-dir", - "out/host_debug", + "out/ci/host_debug", "--zip" ], "script": "flutter/sky/tools/create_macos_gen_snapshots.py" @@ -411,9 +424,9 @@ "--dst", "out/profile/snapshot", "--arm64-out-dir", - "out/mac_profile_arm64", + "out/ci/mac_profile_arm64", "--x64-out-dir", - "out/host_profile", + "out/ci/host_profile", "--zip" ], "script": "flutter/sky/tools/create_macos_gen_snapshots.py" @@ -424,9 +437,9 @@ "--dst", "out/release/snapshot", "--arm64-out-dir", - "out/mac_release_arm64", + "out/ci/mac_release_arm64", "--x64-out-dir", - "out/host_release", + "out/ci/host_release", "--zip" ], "script": "flutter/sky/tools/create_macos_gen_snapshots.py" diff --git a/ci/builders/mac_impeller_cmake_example.json b/ci/builders/mac_impeller_cmake_example.json index 476697f283457..9bc57f27b745e 100644 --- a/ci/builders/mac_impeller_cmake_example.json +++ b/ci/builders/mac_impeller_cmake_example.json @@ -1,7 +1,8 @@ { "builds": [ { - "name": "impeller-cmake-example", + "cas_archive": false, + "name": "ci/impeller-cmake-example", "archives": [], "drone_dimensions": [ "device_type=none", diff --git a/ci/builders/mac_ios_engine.json b/ci/builders/mac_ios_engine.json index a182ae332c041..013a0c5461dfd 100644 --- a/ci/builders/mac_ios_engine.json +++ b/ci/builders/mac_ios_engine.json @@ -7,15 +7,17 @@ "cpu=x86" ], "gn": [ + "--target-dir", + "ci/ios_debug_sim", "--ios", "--runtime-mode", "debug", "--simulator", "--no-lto" ], - "name": "ios_debug_sim", + "name": "ci/ios_debug_sim", "ninja": { - "config": "ios_debug_sim" + "config": "ci/ios_debug_sim" }, "properties": { "$flutter/osx_sdk": { @@ -29,6 +31,8 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_debug_sim_arm64", "--ios", "--runtime-mode", "debug", @@ -36,9 +40,9 @@ "--simulator-cpu=arm64", "--no-lto" ], - "name": "ios_debug_sim_arm64", + "name": "ci/ios_debug_sim_arm64", "ninja": { - "config": "ios_debug_sim_arm64" + "config": "ci/ios_debug_sim_arm64" }, "properties": { "$flutter/osx_sdk": { @@ -52,13 +56,15 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_debug", "--ios", "--runtime-mode", "debug" ], - "name": "ios_debug", + "name": "ci/ios_debug", "ninja": { - "config": "ios_debug", + "config": "ci/ios_debug", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework" ] @@ -75,13 +81,15 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_profile", "--ios", "--runtime-mode", "profile" ], - "name": "ios_profile", + "name": "ci/ios_profile", "ninja": { - "config": "ios_profile", + "config": "ci/ios_profile", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework", "flutter/lib/snapshot:generate_snapshot_bin" @@ -99,13 +107,15 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_release", "--ios", "--runtime-mode", "release" ], - "name": "ios_release", + "name": "ci/ios_release", "ninja": { - "config": "ios_release", + "config": "ci/ios_release", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework", "flutter/lib/snapshot:generate_snapshot_bin" @@ -124,6 +134,8 @@ "cpu=x86" ], "gn": [ + "--target-dir", + "ci/ios_debug_sim_extension_safe", "--ios", "--runtime-mode", "debug", @@ -131,9 +143,9 @@ "--no-lto", "--darwin-extension-safe" ], - "name": "ios_debug_sim_extension_safe", + "name": "ci/ios_debug_sim_extension_safe", "ninja": { - "config": "ios_debug_sim_extension_safe" + "config": "ci/ios_debug_sim_extension_safe" }, "properties": { "$flutter/osx_sdk": { @@ -147,6 +159,8 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_debug_sim_arm64_extension_safe", "--ios", "--runtime-mode", "debug", @@ -155,9 +169,9 @@ "--no-lto", "--darwin-extension-safe" ], - "name": "ios_debug_sim_arm64_extension_safe", + "name": "ci/ios_debug_sim_arm64_extension_safe", "ninja": { - "config": "ios_debug_sim_arm64_extension_safe" + "config": "ci/ios_debug_sim_arm64_extension_safe" }, "properties": { "$flutter/osx_sdk": { @@ -171,14 +185,16 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_debug_extension_safe", "--ios", "--runtime-mode", "debug", "--darwin-extension-safe" ], - "name": "ios_debug_extension_safe", + "name": "ci/ios_debug_extension_safe", "ninja": { - "config": "ios_debug_extension_safe", + "config": "ci/ios_debug_extension_safe", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework" ] @@ -195,14 +211,16 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_profile_extension_safe", "--ios", "--runtime-mode", "profile", "--darwin-extension-safe" ], - "name": "ios_profile_extension_safe", + "name": "ci/ios_profile_extension_safe", "ninja": { - "config": "ios_profile_extension_safe", + "config": "ci/ios_profile_extension_safe", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework", "flutter/lib/snapshot:generate_snapshot_bin" @@ -220,14 +238,16 @@ "os=Mac-13" ], "gn": [ + "--target-dir", + "ci/ios_release_extension_safe", "--ios", "--runtime-mode", "release", "--darwin-extension-safe" ], - "name": "ios_release_extension_safe", + "name": "ci/ios_release_extension_safe", "ninja": { - "config": "ios_release_extension_safe", + "config": "ci/ios_release_extension_safe", "targets": [ "flutter/shell/platform/darwin/ios:flutter_framework", "flutter/lib/snapshot:generate_snapshot_bin" @@ -248,11 +268,11 @@ "--dst", "out/debug", "--arm64-out-dir", - "out/ios_debug", + "out/ci/ios_debug", "--simulator-x64-out-dir", - "out/ios_debug_sim", + "out/ci/ios_debug_sim", "--simulator-arm64-out-dir", - "out/ios_debug_sim_arm64" + "out/ci/ios_debug_sim_arm64" ], "script": "flutter/sky/tools/create_full_ios_framework.py", "language": "python3" @@ -263,11 +283,11 @@ "--dst", "out/profile", "--arm64-out-dir", - "out/ios_profile", + "out/ci/ios_profile", "--simulator-x64-out-dir", - "out/ios_debug_sim", + "out/ci/ios_debug_sim", "--simulator-arm64-out-dir", - "out/ios_debug_sim_arm64" + "out/ci/ios_debug_sim_arm64" ], "script": "flutter/sky/tools/create_full_ios_framework.py", "language": "python3" @@ -278,11 +298,11 @@ "--dst", "out/release", "--arm64-out-dir", - "out/ios_release", + "out/ci/ios_release", "--simulator-x64-out-dir", - "out/ios_debug_sim", + "out/ci/ios_debug_sim", "--simulator-arm64-out-dir", - "out/ios_debug_sim_arm64", + "out/ci/ios_debug_sim_arm64", "--dsym", "--strip" ], @@ -295,7 +315,7 @@ "--dst", "out/release", "--arm64-out-dir", - "out/ios_release" + "out/ci/ios_release" ], "script": "flutter/sky/tools/create_macos_gen_snapshots.py", "language": "python3" @@ -303,7 +323,8 @@ { "name": "Verify-export-symbols-release-binaries", "parameters": [ - "src/out" + "src/out/ci", + "src/flutter/buildtools" ], "script": "flutter/testing/symbols/verify_exported.dart", "language": "dart" diff --git a/ci/builders/mac_unopt.json b/ci/builders/mac_unopt.json index ed7a8da7d7408..e7acb1e75496f 100644 --- a/ci/builders/mac_unopt.json +++ b/ci/builders/mac_unopt.json @@ -12,6 +12,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_debug_unopt", "--runtime-mode", "debug", "--unoptimized", @@ -22,9 +24,9 @@ "--no-goma", "--xcode-symlinks" ], - "name": "host_debug_unopt", + "name": "ci/host_debug_unopt", "ninja": { - "config": "host_debug_unopt", + "config": "ci/host_debug_unopt", "targets": [] }, "properties": { @@ -39,7 +41,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug_unopt", + "ci/host_debug_unopt", "--type", "dart,dart-host,engine", "--engine-capture-core-dump" @@ -80,11 +82,11 @@ "--no-goma", "--xcode-symlinks", "--target-dir", - "ios_debug_unopt_sim" + "ci/ios_debug_unopt_sim" ], - "name": "ios_debug_unopt_sim", + "name": "ci/ios_debug_unopt_sim", "ninja": { - "config": "ios_debug_unopt_sim", + "config": "ci/ios_debug_unopt_sim", "targets": [ "flutter/testing/scenario_app", "flutter/shell/platform/darwin/ios:ios_test_flutter" @@ -97,18 +99,18 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "ios_debug_unopt_sim", + "ci/ios_debug_unopt_sim", "--type", "objc", "--engine-capture-core-dump", "--ios-variant", - "ios_debug_unopt_sim" + "ci/ios_debug_unopt_sim" ] }, { "name": "Scenario App Integration Tests", "parameters": [ - "ios_debug_unopt_sim" + "ci/ios_debug_unopt_sim" ], "script": "flutter/testing/scenario_app/run_ios_tests.sh" } @@ -125,22 +127,24 @@ "use_rbe": true }, "gn": [ - "--runtime-mode", - "debug", - "--unoptimized", - "--no-lto", - "--prebuilt-dart-sdk", - "--force-mac-arm64", - "--mac-cpu", - "arm64", - "--rbe", - "--no-goma", - "--xcode-symlinks", - "--use-glfw-swiftshader" + "--target-dir", + "ci/host_debug_unopt_arm64", + "--runtime-mode", + "debug", + "--unoptimized", + "--no-lto", + "--prebuilt-dart-sdk", + "--force-mac-arm64", + "--mac-cpu", + "arm64", + "--rbe", + "--no-goma", + "--xcode-symlinks", + "--use-glfw-swiftshader" ], - "name": "host_debug_unopt_arm64", + "name": "ci/host_debug_unopt_arm64", "ninja": { - "config": "host_debug_unopt_arm64", + "config": "ci/host_debug_unopt_arm64", "targets": [ ] }, @@ -156,7 +160,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug_unopt_arm64", + "ci/host_debug_unopt_arm64", "--type", "dart,dart-host,engine,impeller-golden", "--engine-capture-core-dump" @@ -195,11 +199,11 @@ "--no-goma", "--xcode-symlinks", "--target-dir", - "ios_debug_unopt_sim_arm64" + "ci/ios_debug_unopt_sim_arm64" ], - "name": "ios_debug_unopt_sim_arm64", + "name": "ci/ios_debug_unopt_sim_arm64", "ninja": { - "config": "ios_debug_unopt_sim_arm64", + "config": "ci/ios_debug_unopt_sim_arm64", "targets": [ "flutter/testing/scenario_app", "flutter/shell/platform/darwin/ios:ios_test_flutter" @@ -212,18 +216,18 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "ios_debug_unopt_sim_arm64", + "ci/ios_debug_unopt_sim_arm64", "--type", "objc", "--engine-capture-core-dump", "--ios-variant", - "ios_debug_unopt_sim_arm64" + "ci/ios_debug_unopt_sim_arm64" ] }, { "name": "Scenario App Integration Tests", "parameters": [ - "ios_debug_unopt_sim_arm64" + "ci/ios_debug_unopt_sim_arm64" ], "script": "flutter/testing/scenario_app/run_ios_tests.sh" } @@ -262,11 +266,11 @@ "--no-goma", "--xcode-symlinks", "--target-dir", - "ios_debug_unopt_sim_arm64_extension_safe" + "ci/ios_debug_unopt_sim_arm64_extension_safe" ], - "name": "ios_debug_unopt_sim_arm64_extension_safe", + "name": "ci/ios_debug_unopt_sim_arm64_extension_safe", "ninja": { - "config": "ios_debug_unopt_sim_arm64_extension_safe", + "config": "ci/ios_debug_unopt_sim_arm64_extension_safe", "targets": [ "flutter/testing/scenario_app", "flutter/shell/platform/darwin/ios:ios_test_flutter" @@ -279,18 +283,18 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "ios_debug_unopt_sim_arm64_extension_safe", + "ci/ios_debug_unopt_sim_arm64_extension_safe", "--type", "objc", "--engine-capture-core-dump", "--ios-variant", - "ios_debug_unopt_sim_arm64_extension_safe" + "ci/ios_debug_unopt_sim_arm64_extension_safe" ] }, { "name": "Scenario App Integration Tests", "parameters": [ - "ios_debug_unopt_sim_arm64_extension_safe" + "ci/ios_debug_unopt_sim_arm64_extension_safe" ], "script": "flutter/testing/scenario_app/run_ios_tests.sh" } diff --git a/ci/builders/mac_unopt_debug_no_rbe.json b/ci/builders/mac_unopt_debug_no_rbe.json index 9d31974457109..7287e8990df66 100644 --- a/ci/builders/mac_unopt_debug_no_rbe.json +++ b/ci/builders/mac_unopt_debug_no_rbe.json @@ -25,11 +25,11 @@ "--no-goma", "--xcode-symlinks", "--target-dir", - "mac_unopt_debug_no_rbe" + "ci/mac_unopt_debug_no_rbe" ], - "name": "mac_unopt_debug_no_rbe", + "name": "ci/mac_unopt_debug_no_rbe", "ninja": { - "config": "mac_unopt_debug_no_rbe", + "config": "ci/mac_unopt_debug_no_rbe", "targets": ["flutter/tools/font_subset"] }, "properties": { @@ -42,7 +42,10 @@ "language": "dart", "name": "clangd", "script": "flutter/tools/clangd_check/bin/main.dart", - "parameters": ["--clangd=buildtools/mac-x64/clang/bin/clangd"] + "parameters": [ + "--clangd=buildtools/mac-x64/clang/bin/clangd", + "--compile-commands-dir=../out/ci/mac_unopt_debug_no_rbe" + ] } ] } diff --git a/ci/builders/standalone/linux_benchmarks.json b/ci/builders/standalone/linux_benchmarks.json index 1f09c3c131a48..36ebfc464e91a 100644 --- a/ci/builders/standalone/linux_benchmarks.json +++ b/ci/builders/standalone/linux_benchmarks.json @@ -8,6 +8,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_release_benchmarks", "--runtime-mode", "release", "--prebuilt-dart-sdk", @@ -15,9 +17,9 @@ "--rbe", "--no-goma" ], - "name": "host_release", + "name": "ci/host_release_benchmarks", "ninja": { - "config": "host_release", + "config": "ci/host_release_benchmarks", "targets": [ "flutter/build/dart:copy_dart_sdk", "flutter/display_list:display_list_benchmarks", @@ -40,7 +42,10 @@ { "language": "bash", "name": "Generate metrics test", - "script": "flutter/testing/benchmark/generate_metrics.sh" + "script": "flutter/testing/benchmark/generate_metrics.sh", + "parameters": [ + "ci/host_release_benchmarks" + ] }, { "contexts": [ @@ -48,7 +53,10 @@ ], "language": "bash", "name": "Upload metrics", - "script": "flutter/testing/benchmark/upload_metrics.sh" + "script": "flutter/testing/benchmark/upload_metrics.sh", + "parameters": [ + "ci/host_release_benchmarks" + ] } ] } diff --git a/ci/builders/standalone/windows_unopt.json b/ci/builders/standalone/windows_unopt.json index 3af977a0ef960..317d7ecc1e9a9 100644 --- a/ci/builders/standalone/windows_unopt.json +++ b/ci/builders/standalone/windows_unopt.json @@ -14,6 +14,8 @@ } ], "gn": [ + "--target-dir", + "ci/host_debug_unopt", "--runtime-mode", "debug", "--unoptimized", @@ -21,9 +23,9 @@ "--rbe", "--no-goma" ], - "name": "host_debug_unopt", + "name": "ci\\host_debug_unopt", "ninja": { - "config": "host_debug_unopt" + "config": "ci/host_debug_unopt" }, "tests": [ { @@ -32,7 +34,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug_unopt", + "ci/host_debug_unopt", "--type", "engine", "--engine-capture-core-dump" diff --git a/ci/builders/windows_android_aot_engine.json b/ci/builders/windows_android_aot_engine.json index a35dad5ea2777..b1bc13d4438b4 100644 --- a/ci/builders/windows_android_aot_engine.json +++ b/ci/builders/windows_android_aot_engine.json @@ -3,12 +3,12 @@ { "archives": [ { - "base_path": "out/android_profile/zip_archives/", + "base_path": "out/ci/android_profile/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile/zip_archives/android-arm-profile/windows-x64.zip" + "out/ci/android_profile/zip_archives/android-arm-profile/windows-x64.zip" ], - "name": "android_profile", + "name": "ci/android_profile", "realm": "production" } ], @@ -20,15 +20,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile", "--runtime-mode", "profile", "--android", "--no-goma", "--rbe" ], - "name": "android_profile", + "name": "ci\\android_profile", "ninja": { - "config": "android_profile", + "config": "ci/android_profile", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] @@ -37,12 +39,12 @@ { "archives": [ { - "base_path": "out/android_profile_arm64/zip_archives/", + "base_path": "out/ci/android_profile_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile_arm64/zip_archives/android-arm64-profile/windows-x64.zip" + "out/ci/android_profile_arm64/zip_archives/android-arm64-profile/windows-x64.zip" ], - "name": "android_profile_arm64", + "name": "ci/android_profile_arm64", "realm": "production" } ], @@ -54,6 +56,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile_arm64", "--runtime-mode", "profile", "--android", @@ -61,9 +65,9 @@ "--no-goma", "--rbe" ], - "name": "android_profile_arm64", + "name": "ci\\android_profile_arm64", "ninja": { - "config": "android_profile_arm64", + "config": "ci/android_profile_arm64", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] @@ -72,12 +76,12 @@ { "archives": [ { - "base_path": "out/android_profile_x64/zip_archives/", + "base_path": "out/ci/android_profile_x64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_profile_x64/zip_archives/android-x64-profile/windows-x64.zip" + "out/ci/android_profile_x64/zip_archives/android-x64-profile/windows-x64.zip" ], - "name": "android_profile_x64", + "name": "ci/android_profile_x64", "realm": "production" } ], @@ -89,6 +93,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_profile_x64", "--runtime-mode", "profile", "--android", @@ -96,9 +102,9 @@ "--no-goma", "--rbe" ], - "name": "android_profile_x64", + "name": "ci\\android_profile_x64", "ninja": { - "config": "android_profile_x64", + "config": "ci/android_profile_x64", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] @@ -107,12 +113,12 @@ { "archives": [ { - "base_path": "out/android_release/zip_archives/", + "base_path": "out/ci/android_release/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release/zip_archives/android-arm-release/windows-x64.zip" + "out/ci/android_release/zip_archives/android-arm-release/windows-x64.zip" ], - "name": "android_release", + "name": "ci/android_release", "realm": "production" } ], @@ -124,15 +130,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release", "--runtime-mode", "release", "--android", "--no-goma", "--rbe" ], - "name": "android_release", + "name": "ci\\android_release", "ninja": { - "config": "android_release", + "config": "ci/android_release", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] @@ -141,12 +149,12 @@ { "archives": [ { - "base_path": "out/android_release_arm64/zip_archives/", + "base_path": "out/ci/android_release_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release_arm64/zip_archives/android-arm64-release/windows-x64.zip" + "out/ci/android_release_arm64/zip_archives/android-arm64-release/windows-x64.zip" ], - "name": "android_release_arm64", + "name": "ci/android_release_arm64", "realm": "production" } ], @@ -158,6 +166,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release_arm64", "--runtime-mode", "release", "--android", @@ -165,9 +175,9 @@ "--no-goma", "--rbe" ], - "name": "android_release_arm64", + "name": "ci\\android_release_arm64", "ninja": { - "config": "android_release_arm64", + "config": "ci/android_release_arm64", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] @@ -176,12 +186,12 @@ { "archives": [ { - "base_path": "out/android_release_x64/zip_archives/", + "base_path": "out/ci/android_release_x64/zip_archives/", "type": "gcs", "include_paths": [ - "out/android_release_x64/zip_archives/android-x64-release/windows-x64.zip" + "out/ci/android_release_x64/zip_archives/android-x64-release/windows-x64.zip" ], - "name": "android_release_x64", + "name": "ci/android_release_x64", "realm": "production" } ], @@ -193,6 +203,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/android_release_x64", "--runtime-mode", "release", "--android", @@ -200,9 +212,9 @@ "--no-goma", "--rbe" ], - "name": "android_release_x64", + "name": "ci\\android_release_x64", "ninja": { - "config": "android_release_x64", + "config": "ci/android_release_x64", "targets": [ "flutter/build/archives:archive_win_gen_snapshot" ] diff --git a/ci/builders/windows_arm_host_engine.json b/ci/builders/windows_arm_host_engine.json index 8912dade7ef74..e2f316e7fb66f 100644 --- a/ci/builders/windows_arm_host_engine.json +++ b/ci/builders/windows_arm_host_engine.json @@ -3,17 +3,17 @@ { "archives": [ { - "base_path": "out/host_debug_arm64/zip_archives/", + "base_path": "out/ci/host_debug_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_debug_arm64/zip_archives/windows-arm64/artifacts.zip", - "out/host_debug_arm64/zip_archives/windows-arm64/windows-arm64-embedder.zip", - "out/host_debug_arm64/zip_archives/windows-arm64/font-subset.zip", - "out/host_debug_arm64/zip_archives/dart-sdk-windows-arm64.zip", - "out/host_debug_arm64/zip_archives/windows-arm64-debug/windows-arm64-flutter.zip", - "out/host_debug_arm64/zip_archives/windows-arm64/flutter-cpp-client-wrapper.zip" + "out/ci/host_debug_arm64/zip_archives/windows-arm64/artifacts.zip", + "out/ci/host_debug_arm64/zip_archives/windows-arm64/windows-arm64-embedder.zip", + "out/ci/host_debug_arm64/zip_archives/windows-arm64/font-subset.zip", + "out/ci/host_debug_arm64/zip_archives/dart-sdk-windows-arm64.zip", + "out/ci/host_debug_arm64/zip_archives/windows-arm64-debug/windows-arm64-flutter.zip", + "out/ci/host_debug_arm64/zip_archives/windows-arm64/flutter-cpp-client-wrapper.zip" ], - "name": "host_debug_arm64", + "name": "ci/host_debug_arm64", "realm": "production" } ], @@ -26,6 +26,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_debug_arm64", "--runtime-mode", "debug", "--no-lto", @@ -34,9 +36,9 @@ "--no-goma", "--rbe" ], - "name": "host_debug_arm64", + "name": "ci\\host_debug_arm64", "ninja": { - "config": "host_debug_arm64", + "config": "ci/host_debug_arm64", "targets": [ "flutter/build/archives:artifacts", "flutter/build/archives:embedder", @@ -50,12 +52,12 @@ { "archives": [ { - "base_path": "out/host_profile_arm64/zip_archives/", + "base_path": "out/ci/host_profile_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_profile_arm64/zip_archives/windows-arm64-profile/windows-arm64-flutter.zip" + "out/ci/host_profile_arm64/zip_archives/windows-arm64-profile/windows-arm64-flutter.zip" ], - "name": "host_profile_arm64", + "name": "ci/host_profile_arm64", "realm": "production" } ], @@ -68,6 +70,8 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_profile_arm64", "--runtime-mode", "profile", "--no-lto", @@ -76,9 +80,9 @@ "--no-goma", "--rbe" ], - "name": "host_profile_arm64", + "name": "ci\\host_profile_arm64", "ninja": { - "config": "host_profile_arm64", + "config": "ci/host_profile_arm64", "targets": [ "windows", "gen_snapshot", @@ -89,12 +93,12 @@ { "archives": [ { - "base_path": "out/host_release_arm64/zip_archives/", + "base_path": "out/ci/host_release_arm64/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_release_arm64/zip_archives/windows-arm64-release/windows-arm64-flutter.zip" + "out/ci/host_release_arm64/zip_archives/windows-arm64-release/windows-arm64-flutter.zip" ], - "name": "host_profile_arm64", + "name": "ci/host_profile_arm64", "realm": "production" } ], @@ -108,6 +112,8 @@ }, "generators": {}, "gn": [ + "--target-dir", + "ci/host_release_arm64", "--runtime-mode", "release", "--no-lto", @@ -116,9 +122,9 @@ "--no-goma", "--rbe" ], - "name": "host_release_arm64", + "name": "ci\\host_release_arm64", "ninja": { - "config": "host_release_arm64", + "config": "ci/host_release_arm64", "targets": [ "windows", "gen_snapshot", diff --git a/ci/builders/windows_host_engine.json b/ci/builders/windows_host_engine.json index bca555a9f4499..a8f1f99c89e76 100644 --- a/ci/builders/windows_host_engine.json +++ b/ci/builders/windows_host_engine.json @@ -3,17 +3,17 @@ { "archives": [ { - "base_path": "out/host_debug/zip_archives/", + "base_path": "out/ci/host_debug/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_debug/zip_archives/windows-x64/artifacts.zip", - "out/host_debug/zip_archives/windows-x64/windows-x64-embedder.zip", - "out/host_debug/zip_archives/windows-x64/font-subset.zip", - "out/host_debug/zip_archives/dart-sdk-windows-x64.zip", - "out/host_debug/zip_archives/windows-x64-debug/windows-x64-flutter.zip", - "out/host_debug/zip_archives/windows-x64/flutter-cpp-client-wrapper.zip" + "out/ci/host_debug/zip_archives/windows-x64/artifacts.zip", + "out/ci/host_debug/zip_archives/windows-x64/windows-x64-embedder.zip", + "out/ci/host_debug/zip_archives/windows-x64/font-subset.zip", + "out/ci/host_debug/zip_archives/dart-sdk-windows-x64.zip", + "out/ci/host_debug/zip_archives/windows-x64-debug/windows-x64-flutter.zip", + "out/ci/host_debug/zip_archives/windows-x64/flutter-cpp-client-wrapper.zip" ], - "name": "host_debug", + "name": "ci/host_debug", "realm": "production" } ], @@ -26,15 +26,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_debug", "--runtime-mode", "debug", "--no-lto", "--no-goma", "--rbe" ], - "name": "host_debug", + "name": "ci\\host_debug", "ninja": { - "config": "host_debug", + "config": "ci/host_debug", "targets": [ "flutter:unittests", "flutter/build/archives:artifacts", @@ -52,7 +54,7 @@ "script": "flutter/testing/run_tests.py", "parameters": [ "--variant", - "host_debug", + "ci/host_debug", "--type", "engine" ] @@ -62,12 +64,12 @@ { "archives": [ { - "base_path": "out/host_profile/zip_archives/", + "base_path": "out/ci/host_profile/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_profile/zip_archives/windows-x64-profile/windows-x64-flutter.zip" + "out/ci/host_profile/zip_archives/windows-x64-profile/windows-x64-flutter.zip" ], - "name": "host_profile", + "name": "ci/host_profile", "realm": "production" } ], @@ -80,15 +82,17 @@ "use_rbe": true }, "gn": [ + "--target-dir", + "ci/host_profile", "--runtime-mode", "profile", "--no-lto", "--no-goma", "--rbe" ], - "name": "host_profile", + "name": "ci\\host_profile", "ninja": { - "config": "host_profile", + "config": "ci/host_profile", "targets": [ "windows", "gen_snapshot", @@ -99,12 +103,12 @@ { "archives": [ { - "base_path": "out/host_release/zip_archives/", + "base_path": "out/ci/host_release/zip_archives/", "type": "gcs", "include_paths": [ - "out/host_release/zip_archives/windows-x64-release/windows-x64-flutter.zip" + "out/ci/host_release/zip_archives/windows-x64-release/windows-x64-flutter.zip" ], - "name": "host_release", + "name": "ci/host_release", "realm": "production" } ], @@ -118,15 +122,17 @@ }, "generators": {}, "gn": [ + "--target-dir", + "ci/host_release", "--runtime-mode", "release", "--no-lto", "--no-goma", "--rbe" ], - "name": "host_release", + "name": "ci\\host_release", "ninja": { - "config": "host_release", + "config": "ci/host_release", "targets": [ "windows", "gen_snapshot", diff --git a/testing/BUILD.gn b/testing/BUILD.gn index 28dab99a0b301..35251252f86b2 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn @@ -101,8 +101,7 @@ source_set("skia") { } dart_snapshot_kernel("vmservice_kernel") { - dart_main = - rebase_path("//flutter/shell/vmservice/empty.dart", root_build_dir) + dart_main = "//flutter/shell/vmservice/empty.dart" dart_kernel = "$target_gen_dir/assets/vmservice_kernel.bin" } diff --git a/testing/benchmark/generate_metrics.sh b/testing/benchmark/generate_metrics.sh index 173f28dda9cb8..eddd11e9bfe43 100644 --- a/testing/benchmark/generate_metrics.sh +++ b/testing/benchmark/generate_metrics.sh @@ -4,17 +4,19 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # -# This script expects $ENGINE_PATH to be set. It is currently used only +# This script expects ${ENGINE_PATH} to be set. It is currently used only # by automation to collect and upload metrics. set -ex -$ENGINE_PATH/src/out/host_release/txt_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/txt_benchmarks.json -$ENGINE_PATH/src/out/host_release/fml_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/fml_benchmarks.json -$ENGINE_PATH/src/out/host_release/shell_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/shell_benchmarks.json -$ENGINE_PATH/src/out/host_release/ui_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/ui_benchmarks.json -$ENGINE_PATH/src/out/host_release/display_list_builder_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/display_list_builder_benchmarks.json -$ENGINE_PATH/src/out/host_release/display_list_region_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/display_list_region_benchmarks.json -$ENGINE_PATH/src/out/host_release/display_list_transform_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/display_list_transform_benchmarks.json -$ENGINE_PATH/src/out/host_release/geometry_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/geometry_benchmarks.json -$ENGINE_PATH/src/out/host_release/canvas_benchmarks --benchmark_format=json > $ENGINE_PATH/src/out/host_release/canvas_benchmarks.json +VARIANT=$1 + +${ENGINE_PATH}/src/out/${VARIANT}/txt_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/txt_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/fml_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/fml_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/shell_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/shell_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/ui_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/ui_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/display_list_builder_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/display_list_builder_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/display_list_region_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/display_list_region_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/display_list_transform_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/display_list_transform_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/geometry_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/geometry_benchmarks.json +${ENGINE_PATH}/src/out/${VARIANT}/canvas_benchmarks --benchmark_format=json > ${ENGINE_PATH}/src/out/${VARIANT}/canvas_benchmarks.json diff --git a/testing/benchmark/upload_metrics.sh b/testing/benchmark/upload_metrics.sh index a2a8f28a4f876..b32cd4b334a60 100644 --- a/testing/benchmark/upload_metrics.sh +++ b/testing/benchmark/upload_metrics.sh @@ -43,22 +43,25 @@ SRC_DIR="$(cd "$SCRIPT_DIR/../../.."; pwd -P)" DART_BIN=$(dart_bin "$SRC_DIR") DART="${DART_BIN}/dart" +VARIANT=$1 +shift 1 + cd "$SCRIPT_DIR" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/txt_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/txt_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/fml_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/fml_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/shell_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/shell_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/ui_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/ui_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/display_list_builder_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/display_list_builder_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/display_list_region_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/display_list_region_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/display_list_transform_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/display_list_transform_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/geometry_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/geometry_benchmarks.json "$@" "$DART" --disable-dart-dev bin/parse_and_send.dart \ - --json $ENGINE_PATH/src/out/host_release/canvas_benchmarks.json "$@" + --json $ENGINE_PATH/src/out/${VARIANT}/canvas_benchmarks.json "$@" diff --git a/testing/dart/BUILD.gn b/testing/dart/BUILD.gn index 90b4ee96f4295..f67dad80f0b4e 100644 --- a/testing/dart/BUILD.gn +++ b/testing/dart/BUILD.gn @@ -55,7 +55,7 @@ tests = [ foreach(test, tests) { flutter_build_dir = rebase_path("$root_gen_dir") - flutter_src_dir = rebase_path("$root_out_dir/../../flutter") + flutter_src_dir = rebase_path("//flutter") skia_gold_work_dir = rebase_path("$root_gen_dir/skia_gold_$test") flutter_frontend_server("compile_$test") { main_dart = test diff --git a/testing/fuchsia/run_tests.py b/testing/fuchsia/run_tests.py index f7155e5563cc0..f315a6887c57e 100755 --- a/testing/fuchsia/run_tests.py +++ b/testing/fuchsia/run_tests.py @@ -142,7 +142,7 @@ def _get_test_runner(runner_args: argparse.Namespace, *_) -> TestRunner: logging.basicConfig(level=logging.INFO) logging.info('Running tests in %s', OUT_DIR) sys.argv.append('--out-dir=' + OUT_DIR) - if VARIANT.endswith('_arm64'): + if VARIANT.endswith('_arm64') or VARIANT.endswith('_arm64_tester'): sys.argv.append('--product=terminal.qemu-arm64') # The 'flutter-test-type' is a place holder and has no specific meaning; the # _get_test_runner is overrided. diff --git a/testing/run_tests.py b/testing/run_tests.py index 25040a58aa97a..9ec10f57e20b8 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -1326,7 +1326,12 @@ def main(): run_engine_benchmarks(build_dir, engine_filter) variants_to_skip = ['host_release', 'host_profile'] - if ('engine' in types or 'font-subset' in types) and args.variant not in variants_to_skip: + + def should_skip(variant): + matches = [variant for variant in variants_to_skip if variant in args.variant] + return len(matches) > 0 + + if ('engine' in types or 'font-subset' in types) and not should_skip(args.variant): cmd = ['python3', 'test.py', '--variant', args.variant] if 'arm64' in args.variant: cmd += ['--target-cpu', 'arm64'] diff --git a/tools/clang_tidy/test/clang_tidy_test.dart b/tools/clang_tidy/test/clang_tidy_test.dart index edcc4c9af647d..cf3e575f0c82d 100644 --- a/tools/clang_tidy/test/clang_tidy_test.dart +++ b/tools/clang_tidy/test/clang_tidy_test.dart @@ -213,6 +213,7 @@ Future main(List args) async { test('clang-tidy specified', () async { _withTempFile('shard-id-valid', (String path) { final Options options = Options.fromCommandLine( [ + '--compile-commands=$path', '--clang-tidy=foo/bar', ],); expect(options.clangTidyPath, isNotNull); diff --git a/tools/clangd_check/bin/main.dart b/tools/clangd_check/bin/main.dart index c97ae4a2090f6..d2e19dbb5c7dd 100644 --- a/tools/clangd_check/bin/main.dart +++ b/tools/clangd_check/bin/main.dart @@ -58,10 +58,11 @@ void main(List args) { final String checkFile; if (entry case { 'command': final String command, + 'directory': final String directory, 'file': final String file, }) { // Given a path like ../../flutter/foo.cc, we want to check foo.cc. - checkFile = p.split(file).skip(3).join(p.separator); + checkFile = p.join(directory, file); // On CI, the command path is different from the local path. // Find the engine root and derive the clangd path from there. if (clangd == null) { diff --git a/tools/fuchsia/build_fuchsia_artifacts.py b/tools/fuchsia/build_fuchsia_artifacts.py index e170a699555f5..8cb3ea25d39a3 100755 --- a/tools/fuchsia/build_fuchsia_artifacts.py +++ b/tools/fuchsia/build_fuchsia_artifacts.py @@ -22,7 +22,7 @@ _script_dir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..')) _src_root_dir = os.path.join(_script_dir, '..', '..', '..') -_out_dir = os.path.join(_src_root_dir, 'out') +_out_dir = os.path.join(_src_root_dir, 'out', 'ci') _bucket_directory = os.path.join(_out_dir, 'fuchsia_bucket') diff --git a/tools/pkg/engine_build_configs/bin/check.dart b/tools/pkg/engine_build_configs/bin/check.dart index 7c3e759311a71..2e057e93f4597 100644 --- a/tools/pkg/engine_build_configs/bin/check.dart +++ b/tools/pkg/engine_build_configs/bin/check.dart @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:io' as io; +import 'dart:io' as io show Directory, exitCode, stderr; import 'package:engine_build_configs/engine_build_configs.dart'; import 'package:engine_repo_tools/engine_repo_tools.dart'; import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; // Usage: // $ dart bin/check.dart [/path/to/engine/src] @@ -55,30 +56,102 @@ void main(List args) { } // Check the parsed build configs for validity. + final List invalidErrors = checkForInvalidConfigs(configs); + if (invalidErrors.isNotEmpty) { + invalidErrors.forEach(io.stderr.writeln); + io.exitCode = 1; + } + + // We require all builds within a builder config to be uniquely named. + final List duplicateErrors = checkForDuplicateConfigs(configs); + if (duplicateErrors.isNotEmpty) { + duplicateErrors.forEach(io.stderr.writeln); + io.exitCode = 1; + } + + // We require all builds to be named in a way that is understood by et. + final List buildNameErrors = checkForInvalidBuildNames(configs); + if (buildNameErrors.isNotEmpty) { + buildNameErrors.forEach(io.stderr.writeln); + io.exitCode = 1; + } +} + +// This check ensures that all the json files were deserialized without errors. +List checkForInvalidConfigs(Map configs) { + final List errors = []; for (final String name in configs.keys) { final BuilderConfig buildConfig = configs[name]!; final List buildConfigErrors = buildConfig.check(name); if (buildConfigErrors.isNotEmpty) { - io.stderr.writeln('Errors in ${buildConfig.path}:'); - io.exitCode = 1; + errors.add('Errors in ${buildConfig.path}:'); } for (final String error in buildConfigErrors) { - io.stderr.writeln(' $error'); - io.exitCode = 1; + errors.add(' $error'); } } + return errors; +} - // We require all builds within a builder config to be uniquely named. +// Thjs check ensures that json files do not contain builds with duplicate +// names. +List checkForDuplicateConfigs(Map configs) { + final List errors = []; final Map> builderBuildSet = >{}; + _forEachBuild(configs, (String name, BuilderConfig config, Build build) { + final Set builds = builderBuildSet.putIfAbsent(name, () => {}); + if (builds.contains(build.name)) { + errors.add('${build.name} is duplicated in $name\n'); + } else { + builds.add(build.name); + } + }); + return errors; +} + +// This check ensures that builds are named in a way that is understood by +// `et`. +List checkForInvalidBuildNames(Map configs) { + final List errors = []; + + // In local_engine.json, allowed OS names are linux, macos, and windows. + final List osNames = [ + Platform.linux, Platform.macOS, Platform.windows, + ].expand((String s) => ['$s/', '$s\\']).toList(); + + // In all other build json files, allowed prefix names are ci and web_tests. + final List ciNames = [ + 'ci', 'web_tests' + ].expand((String s) => ['$s/', '$s\\']).toList(); + + _forEachBuild(configs, (String name, BuilderConfig config, Build build) { + final List goodPrefixes = name.contains('local_engine') + ? osNames + : ciNames; + if (!goodPrefixes.any(build.name.startsWith)) { + if (name.contains('local_engine')) { + // TODO(zanderso): Check these builds as well after local_engine is + // fixed. + // https://github.com/flutter/flutter/issues/145263 + return; + } + errors.add( + '${build.name} in $name must start with one of ' + '{${goodPrefixes.join(', ')}}', + ); + } + }); + return errors; +} + +void _forEachBuild( + Map configs, + void Function(String configName, BuilderConfig config, Build build) fn, +) { for (final String builderName in configs.keys) { final BuilderConfig builderConfig = configs[builderName]!; - final Set builds = - builderBuildSet.putIfAbsent(builderName, () => {}); for (final Build build in builderConfig.builds) { - if (builds.contains(build.name)) { - io.stderr.writeln('${build.name} is duplicated in $builderName\n'); - io.exitCode = 1; - } + fn(builderName, builderConfig, build); } } } From ea2d1db4a3cee24926060d32cddb172d4fafe61e Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:43:57 -0700 Subject: [PATCH 48/49] Replace LinkedLists that are used as a queue in android FlutterRenderer with ArrayDeques (#51494) Inspired by https://github.com/flutter/engine/pull/50767. [As their documentation notes](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html), `ArrayDeque`s are generally faster than LinkedList when used as a queue. Fixes https://github.com/flutter/flutter/issues/143721 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../flutter/embedding/engine/renderer/FlutterRenderer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index df0e5b556a0d3..d8bdae1600358 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -28,11 +28,11 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -441,7 +441,7 @@ final class ImageReaderSurfaceProducer private Object lock = new Object(); // REQUIRED: The following fields must only be accessed when lock is held. - private final LinkedList imageReaderQueue = new LinkedList(); + private final ArrayDeque imageReaderQueue = new ArrayDeque(); private final HashMap perImageReaders = new HashMap(); private PerImage lastDequeuedImage = null; @@ -461,7 +461,7 @@ public PerImage(Image image, long queuedTime) { /** Internal class: state held per ImageReader. */ private class PerImageReader { public final ImageReader reader; - private final LinkedList imageQueue = new LinkedList(); + private final ArrayDeque imageQueue = new ArrayDeque(); private boolean closed = false; private final ImageReader.OnImageAvailableListener onImageAvailableListener = From 687a9a119e04b3aa0aa92d58704cd94a49813454 Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Mon, 29 Apr 2024 22:09:05 -0700 Subject: [PATCH 49/49] Workaround HardwareRenderer breakage in Android 14 (#52370) - Destroy ImageReaders on memory trim. - Unset the VirtualDisplay's surface on memory trim. - On resume, recreate ImageReaders. - On resume, do a dumb little dance and then set the VirtualDisplay's surface Fixes: https://github.com/flutter/flutter/issues/146499 Fixes: https://github.com/flutter/flutter/issues/144219 Internal bug: b/335646931 Android Fix: https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/base/+/27015418 Android 15 will include the fix. Unclear if Android 14 will be patched. --- .../FlutterActivityAndFragmentDelegate.java | 2 + .../engine/renderer/FlutterRenderer.java | 26 ++++++++--- .../platform/PlatformViewsController.java | 19 ++++++++ .../platform/VirtualDisplayController.java | 43 +++++++++++++++++++ .../engine/renderer/FlutterRendererTest.java | 30 ++++++++++++- 5 files changed, 114 insertions(+), 6 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 2f1156704b982..1f6118bfe56c4 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -583,6 +583,7 @@ void onPostResume() { ensureAlive(); if (flutterEngine != null) { updateSystemUiOverlays(); + flutterEngine.getPlatformViewsController().onResume(); } else { Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity."); } @@ -1020,6 +1021,7 @@ void onTrimMemory(int level) { flutterEngine.getSystemChannel().sendMemoryPressureWarning(); } flutterEngine.getRenderer().onTrimMemory(level); + flutterEngine.getPlatformViewsController().onTrimMemory(level); } } diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index d8bdae1600358..d23fd4e326159 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -7,6 +7,7 @@ import static io.flutter.Build.API_LEVELS; import android.annotation.TargetApi; +import android.content.ComponentCallbacks2; import android.graphics.Bitmap; import android.graphics.ImageFormat; import android.graphics.Rect; @@ -414,10 +415,9 @@ final class ImageReaderSurfaceProducer // Flip when debugging to see verbose logs. private static final boolean VERBOSE_LOGS = false; - // If we cleanup the ImageReaders on memory pressure it breaks VirtualDisplay - // backed platform views. Disable for now as this is only necessary to work - // around a Samsung-specific Android 14 bug. - private static final boolean CLEANUP_ON_MEMORY_PRESSURE = false; + // We must always cleanup on memory pressure on Android 14 due to a bug in Android. + // It is safe to do on all versions so we unconditionally have this set to true. + private static final boolean CLEANUP_ON_MEMORY_PRESSURE = true; private final long id; @@ -425,6 +425,8 @@ final class ImageReaderSurfaceProducer // Will be true in tests and on Android API < 33. private boolean ignoringFence = false; + private boolean trimOnMemoryPressure = CLEANUP_ON_MEMORY_PRESSURE; + // The requested width and height are updated by setSize. private int requestedWidth = 1; private int requestedHeight = 1; @@ -438,6 +440,7 @@ final class ImageReaderSurfaceProducer private long lastDequeueTime = 0; private long lastQueueTime = 0; private long lastScheduleTime = 0; + private int numTrims = 0; private Object lock = new Object(); // REQUIRED: The following fields must only be accessed when lock is held. @@ -654,9 +657,15 @@ PerImage dequeueImage() { @Override public void onTrimMemory(int level) { - if (!CLEANUP_ON_MEMORY_PRESSURE) { + if (!trimOnMemoryPressure) { + return; + } + if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { return; } + synchronized (lock) { + numTrims++; + } cleanup(); createNewReader = true; } @@ -873,6 +882,13 @@ public int numImageReaders() { } } + @VisibleForTesting + public int numTrims() { + synchronized (lock) { + return numTrims; + } + } + @VisibleForTesting public int numImages() { int r = 0; diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index 6e2b2ab250f82..093be1566cb4e 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -9,6 +9,7 @@ import static io.flutter.Build.API_LEVELS; import android.annotation.TargetApi; +import android.content.ComponentCallbacks2; import android.content.Context; import android.content.MutableContextWrapper; import android.os.Build; @@ -1053,6 +1054,24 @@ private void diposeAllViews() { } } + // Invoked when the Android system is requesting we reduce memory usage. + public void onTrimMemory(int level) { + if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { + return; + } + for (VirtualDisplayController vdc : vdControllers.values()) { + vdc.clearSurface(); + } + } + + // Called after the application has been resumed. + // This is where we undo whatever may have been done in onTrimMemory. + public void onResume() { + for (VirtualDisplayController vdc : vdControllers.values()) { + vdc.resetSurface(); + } + } + /** * Disposes a single * diff --git a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java b/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java index 5de42299e00c4..cdde0687a4a99 100644 --- a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java +++ b/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java @@ -284,6 +284,49 @@ public void dispatchTouchEvent(MotionEvent event) { presentation.dispatchTouchEvent(event); } + public void clearSurface() { + virtualDisplay.setSurface(null); + } + + public void resetSurface() { + final int width = getRenderTargetWidth(); + final int height = getRenderTargetHeight(); + final boolean isFocused = getView().isFocused(); + final SingleViewPresentation.PresentationState presentationState = presentation.detachState(); + + // We detach the surface to prevent it being destroyed when releasing the vd. + virtualDisplay.setSurface(null); + virtualDisplay.release(); + final DisplayManager displayManager = + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + int flags = 0; + virtualDisplay = + displayManager.createVirtualDisplay( + "flutter-vd#" + viewId, + width, + height, + densityDpi, + renderTarget.getSurface(), + flags, + callback, + null /* handler */); + // Create a new SingleViewPresentation and show() it before we cancel() the existing + // presentation. Calling show() and cancel() in this order fixes + // https://github.com/flutter/flutter/issues/26345 and maintains seamless transition + // of the contents of the presentation. + SingleViewPresentation newPresentation = + new SingleViewPresentation( + context, + virtualDisplay.getDisplay(), + accessibilityEventsDelegate, + presentationState, + focusChangeListener, + isFocused); + newPresentation.show(); + presentation.cancel(); + presentation = newPresentation; + } + static class OneTimeOnDrawListener implements ViewTreeObserver.OnDrawListener { static void schedule(View view, Runnable runnable) { OneTimeOnDrawListener listener = new OneTimeOnDrawListener(view, runnable); diff --git a/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java b/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java index bc36ed3075f73..f19da788d3759 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java @@ -647,13 +647,41 @@ public void ImageReaderSurfaceProducerTrimMemoryCallback() { assertEquals(1, texture.numImageReaders()); assertEquals(1, texture.numImages()); - // Invoke the onTrimMemory callback. + // Invoke the onTrimMemory callback with level 0. // This should do nothing. texture.onTrimMemory(0); shadowOf(Looper.getMainLooper()).idle(); assertEquals(1, texture.numImageReaders()); assertEquals(1, texture.numImages()); + assertEquals(0, texture.numTrims()); + + // Invoke the onTrimMemory callback with level 40. + // This should result in a trim. + texture.onTrimMemory(40); + shadowOf(Looper.getMainLooper()).idle(); + + assertEquals(0, texture.numImageReaders()); + assertEquals(0, texture.numImages()); + assertEquals(1, texture.numTrims()); + + // Request the surface, this should result in a new image reader. + surface = texture.getSurface(); + assertEquals(1, texture.numImageReaders()); + assertEquals(0, texture.numImages()); + assertEquals(1, texture.numTrims()); + + // Render an image. + canvas = surface.lockHardwareCanvas(); + canvas.drawARGB(255, 255, 0, 0); + surface.unlockCanvasAndPost(canvas); + + // Let callbacks run, this will produce a single frame. + shadowOf(Looper.getMainLooper()).idle(); + + assertEquals(1, texture.numImageReaders()); + assertEquals(1, texture.numImages()); + assertEquals(1, texture.numTrims()); } // A 0x0 ImageReader is a runtime error.