From f31faf34dfb4c7bc8854ffa2e04904d2a87905ae Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 27 Mar 2024 15:26:04 -0700 Subject: [PATCH 1/7] [Impeller] use optimal depth attachment, remove useless barrier. (#51723) We have been transitioning the depth/stencil atttachment to general, even though it can just be in attachment optimal (we never use it as an input attachment). --- ci/licenses_golden/excluded_files | 1 + impeller/renderer/backend/vulkan/BUILD.gn | 1 + .../backend/vulkan/render_pass_builder_vk.cc | 23 +++- .../backend/vulkan/render_pass_builder_vk.h | 10 ++ .../render_pass_builder_vk_unittests.cc | 103 ++++++++++++++++++ .../renderer/backend/vulkan/render_pass_vk.cc | 2 - 6 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 64ac960984cd1..212e9095ac440 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -177,6 +177,7 @@ ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc +../../../flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/swapchain/README.md diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 285c655acaa09..8a00a9c77c1af 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -16,6 +16,7 @@ impeller_component("vulkan_unittests") { "descriptor_pool_vk_unittests.cc", "driver_info_vk_unittests.cc", "fence_waiter_vk_unittests.cc", + "render_pass_builder_vk_unittests.cc", "render_pass_cache_unittests.cc", "resource_manager_vk_unittests.cc", "test/gpu_tracer_unittests.cc", diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc b/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc index 5edd04441553f..b0f29947533eb 100644 --- a/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc @@ -62,8 +62,8 @@ RenderPassBuilderVK& RenderPassBuilderVK::SetDepthStencilAttachment( desc.storeOp = ToVKAttachmentStoreOp(store_action); desc.stencilLoadOp = desc.loadOp; // Not separable in Impeller. desc.stencilStoreOp = desc.storeOp; // Not separable in Impeller. - desc.initialLayout = vk::ImageLayout::eGeneral; - desc.finalLayout = vk::ImageLayout::eGeneral; + desc.initialLayout = vk::ImageLayout::eUndefined; + desc.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; depth_stencil_ = desc; return *this; } @@ -80,8 +80,8 @@ RenderPassBuilderVK& RenderPassBuilderVK::SetStencilAttachment( desc.storeOp = vk::AttachmentStoreOp::eDontCare; desc.stencilLoadOp = ToVKAttachmentLoadOp(load_action); desc.stencilStoreOp = ToVKAttachmentStoreOp(store_action); - desc.initialLayout = vk::ImageLayout::eGeneral; - desc.finalLayout = vk::ImageLayout::eGeneral; + desc.initialLayout = vk::ImageLayout::eUndefined; + desc.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; depth_stencil_ = desc; return *this; } @@ -184,4 +184,19 @@ void InsertBarrierForInputAttachmentRead(const vk::CommandBuffer& buffer, ); } +const std::map& +RenderPassBuilderVK::GetColorAttachments() const { + return colors_; +} + +const std::map& +RenderPassBuilderVK::GetResolves() const { + return resolves_; +} + +const std::optional& +RenderPassBuilderVK::GetDepthStencil() const { + return depth_stencil_; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk.h b/impeller/renderer/backend/vulkan/render_pass_builder_vk.h index 4ed9f1c9c5a39..4ef1924e8fe32 100644 --- a/impeller/renderer/backend/vulkan/render_pass_builder_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk.h @@ -42,6 +42,16 @@ class RenderPassBuilderVK { vk::UniqueRenderPass Build(const vk::Device& device) const; + // Visible for testing. + const std::map& GetColorAttachments() + const; + + // Visible for testing. + const std::map& GetResolves() const; + + // Visible for testing. + const std::optional& GetDepthStencil() const; + private: std::map colors_; std::map resolves_; diff --git a/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc b/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc new file mode 100644 index 0000000000000..03e11a6725ffb --- /dev/null +++ b/impeller/renderer/backend/vulkan/render_pass_builder_vk_unittests.cc @@ -0,0 +1,103 @@ +// 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/testing/testing.h" // IWYU pragma: keep +#include "gtest/gtest.h" +#include "impeller/core/formats.h" +#include "impeller/renderer/backend/vulkan/render_pass_builder_vk.h" +#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" +#include "vulkan/vulkan_enums.hpp" + +namespace impeller { +namespace testing { + +TEST(RenderPassBuilder, CreatesRenderPassWithNoDepthStencil) { + RenderPassBuilderVK builder = RenderPassBuilderVK(); + auto const context = MockVulkanContextBuilder().Build(); + + // Create a single color attachment with a transient depth stencil. + builder.SetColorAttachment(0, PixelFormat::kR8G8B8A8UNormInt, + SampleCount::kCount1, LoadAction::kClear, + StoreAction::kStore); + + auto render_pass = builder.Build(context->GetDevice()); + + EXPECT_TRUE(!!render_pass); + EXPECT_FALSE(builder.GetDepthStencil().has_value()); +} + +TEST(RenderPassBuilder, CreatesRenderPassWithCombinedDepthStencil) { + RenderPassBuilderVK builder = RenderPassBuilderVK(); + auto const context = MockVulkanContextBuilder().Build(); + + // Create a single color attachment with a transient depth stencil. + builder.SetColorAttachment(0, PixelFormat::kR8G8B8A8UNormInt, + SampleCount::kCount1, LoadAction::kClear, + StoreAction::kStore); + builder.SetDepthStencilAttachment(PixelFormat::kD24UnormS8Uint, + SampleCount::kCount1, LoadAction::kDontCare, + StoreAction::kDontCare); + + auto render_pass = builder.Build(context->GetDevice()); + + EXPECT_TRUE(!!render_pass); + + auto maybe_color = builder.GetColorAttachments().find(0u); + ASSERT_NE(maybe_color, builder.GetColorAttachments().end()); + auto color = maybe_color->second; + + EXPECT_EQ(color.initialLayout, vk::ImageLayout::eGeneral); + EXPECT_EQ(color.finalLayout, vk::ImageLayout::eGeneral); + EXPECT_EQ(color.loadOp, vk::AttachmentLoadOp::eClear); + EXPECT_EQ(color.storeOp, vk::AttachmentStoreOp::eStore); + + auto maybe_depth_stencil = builder.GetDepthStencil(); + ASSERT_TRUE(maybe_depth_stencil.has_value()); + if (!maybe_depth_stencil.has_value()) { + return; + } + auto depth_stencil = maybe_depth_stencil.value(); + + EXPECT_EQ(depth_stencil.initialLayout, vk::ImageLayout::eUndefined); + EXPECT_EQ(depth_stencil.finalLayout, + vk::ImageLayout::eDepthStencilAttachmentOptimal); + EXPECT_EQ(depth_stencil.loadOp, vk::AttachmentLoadOp::eDontCare); + EXPECT_EQ(depth_stencil.storeOp, vk::AttachmentStoreOp::eDontCare); + EXPECT_EQ(depth_stencil.stencilLoadOp, vk::AttachmentLoadOp::eDontCare); + EXPECT_EQ(depth_stencil.stencilStoreOp, vk::AttachmentStoreOp::eDontCare); +} + +TEST(RenderPassBuilder, CreatesRenderPassWithOnlyStencil) { + RenderPassBuilderVK builder = RenderPassBuilderVK(); + auto const context = MockVulkanContextBuilder().Build(); + + // Create a single color attachment with a transient depth stencil. + builder.SetColorAttachment(0, PixelFormat::kR8G8B8A8UNormInt, + SampleCount::kCount1, LoadAction::kClear, + StoreAction::kStore); + builder.SetStencilAttachment(PixelFormat::kS8UInt, SampleCount::kCount1, + LoadAction::kDontCare, StoreAction::kDontCare); + + auto render_pass = builder.Build(context->GetDevice()); + + EXPECT_TRUE(!!render_pass); + + auto maybe_depth_stencil = builder.GetDepthStencil(); + ASSERT_TRUE(maybe_depth_stencil.has_value()); + if (!maybe_depth_stencil.has_value()) { + return; + } + auto depth_stencil = maybe_depth_stencil.value(); + + EXPECT_EQ(depth_stencil.initialLayout, vk::ImageLayout::eUndefined); + EXPECT_EQ(depth_stencil.finalLayout, + vk::ImageLayout::eDepthStencilAttachmentOptimal); + EXPECT_EQ(depth_stencil.loadOp, vk::AttachmentLoadOp::eDontCare); + EXPECT_EQ(depth_stencil.storeOp, vk::AttachmentStoreOp::eDontCare); + EXPECT_EQ(depth_stencil.stencilLoadOp, vk::AttachmentLoadOp::eDontCare); + EXPECT_EQ(depth_stencil.stencilStoreOp, vk::AttachmentStoreOp::eDontCare); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 70dedb19a59b9..ba5d68f08e838 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -113,7 +113,6 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( depth->load_action, // depth->store_action // ); - TextureVK::Cast(*depth->texture).SetLayout(barrier); } else if (auto stencil = render_target_.GetStencilAttachment(); stencil.has_value()) { builder.SetStencilAttachment( @@ -122,7 +121,6 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( stencil->load_action, // stencil->store_action // ); - TextureVK::Cast(*stencil->texture).SetLayout(barrier); } if (recycled_renderpass != nullptr) { From 5d13a29822b4ac59f13bda4eaba44f564ee42778 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 27 Mar 2024 15:34:07 -0700 Subject: [PATCH 2/7] [Impeller] render empty filled paths without crashing. (#51713) Fixes https://github.com/flutter/flutter/issues/145823 If we try to render a solid filled empty size path, the subpath division code creates an obscene number of vertices that hits overflow errors. Just No-op instead. --- .../entity/contents/color_source_contents.h | 6 +++ impeller/entity/entity_unittests.cc | 45 +++++++++++++++++++ .../entity/geometry/fill_path_geometry.cc | 35 ++++++++++++++- .../entity/geometry/geometry_unittests.cc | 3 ++ impeller/tessellator/tessellator.cc | 1 + 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h index 4139b0c17af8c..2c1e104562e65 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h @@ -137,6 +137,9 @@ class ColorSourceContents : public Contents { GeometryResult stencil_geometry_result = GetGeometry()->GetPositionBuffer(renderer, entity, pass); + if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) { + return true; + } pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer)); options.primitive_type = stencil_geometry_result.type; @@ -182,6 +185,9 @@ class ColorSourceContents : public Contents { ? geometry.GetPositionUVBuffer(texture_coverage, effect_transform, renderer, entity, pass) : geometry.GetPositionBuffer(renderer, entity, pass); + if (geometry_result.vertex_buffer.vertex_count == 0u) { + return true; + } pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer)); options.primitive_type = geometry_result.type; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 2ec99fc0cc60e..ba3fccbc38e31 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2813,6 +2813,51 @@ TEST_P(EntityTest, FailOnValidationError) { ""); } +TEST_P(EntityTest, CanComputeGeometryForEmptyPathsWithoutCrashing) { + PathBuilder builder = {}; + builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0)); + Path path = builder.TakePath(); + + EXPECT_TRUE(path.GetBoundingBox()->IsEmpty()); + + auto geom = Geometry::MakeFillPath(path); + + Entity entity; + RenderTarget target = + GetContentContext()->GetRenderTargetCache()->CreateOffscreen( + *GetContext(), {1, 1}, 1u); + testing::MockRenderPass render_pass(GetContext(), target); + auto position_result = + geom->GetPositionBuffer(*GetContentContext(), entity, render_pass); + + auto uv_result = + geom->GetPositionUVBuffer(Rect::MakeLTRB(0, 0, 100, 100), Matrix(), + *GetContentContext(), entity, render_pass); + + EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u); + EXPECT_EQ(uv_result.vertex_buffer.vertex_count, 0u); + + EXPECT_EQ(geom->GetResultMode(), GeometryResult::Mode::kNormal); +} + +TEST_P(EntityTest, CanRenderEmptyPathsWithoutCrashing) { + PathBuilder builder = {}; + builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0)); + Path path = builder.TakePath(); + + EXPECT_TRUE(path.GetBoundingBox()->IsEmpty()); + + auto contents = std::make_shared(); + contents->SetGeometry(Geometry::MakeFillPath(path)); + contents->SetColor(Color::Red()); + + Entity entity; + entity.SetTransform(Matrix::MakeScale(GetContentScale())); + entity.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/geometry/fill_path_geometry.cc b/impeller/entity/geometry/fill_path_geometry.cc index 540e056284a33..7f0f807a2fced 100644 --- a/impeller/entity/geometry/fill_path_geometry.cc +++ b/impeller/entity/geometry/fill_path_geometry.cc @@ -6,6 +6,7 @@ #include "fml/logging.h" #include "impeller/core/formats.h" +#include "impeller/core/vertex_buffer.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/geometry/geometry.h" @@ -20,8 +21,22 @@ GeometryResult FillPathGeometry::GetPositionBuffer( const Entity& entity, RenderPass& pass) const { auto& host_buffer = renderer.GetTransientsBuffer(); - VertexBuffer vertex_buffer; + const auto& bounding_box = path_.GetBoundingBox(); + if (bounding_box.has_value() && bounding_box->IsEmpty()) { + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + VertexBuffer{ + .vertex_buffer = {}, + .vertex_count = 0, + .index_type = IndexType::k16bit, + }, + .transform = pass.GetOrthographicTransform() * entity.GetTransform(), + }; + } + + VertexBuffer vertex_buffer; if constexpr (!ContentContext::kEnableStencilThenCover) { if (!path_.IsConvex()) { auto tesselation_result = renderer.GetTessellator()->Tessellate( @@ -79,6 +94,20 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer( RenderPass& pass) const { using VS = TextureFillVertexShader; + const auto& bounding_box = path_.GetBoundingBox(); + if (bounding_box.has_value() && bounding_box->IsEmpty()) { + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + VertexBuffer{ + .vertex_buffer = {}, + .vertex_count = 0, + .index_type = IndexType::k16bit, + }, + .transform = pass.GetOrthographicTransform() * entity.GetTransform(), + }; + } + auto uv_transform = texture_coverage.GetNormalizingTransform() * effect_transform; @@ -139,7 +168,9 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer( } GeometryResult::Mode FillPathGeometry::GetResultMode() const { - if (!ContentContext::kEnableStencilThenCover || path_.IsConvex()) { + const auto& bounding_box = path_.GetBoundingBox(); + if (!ContentContext::kEnableStencilThenCover || path_.IsConvex() || + (bounding_box.has_value() && bounding_box->IsEmpty())) { return GeometryResult::Mode::kNormal; } diff --git a/impeller/entity/geometry/geometry_unittests.cc b/impeller/entity/geometry/geometry_unittests.cc index c56c16613bd57..990b1419659ed 100644 --- a/impeller/entity/geometry/geometry_unittests.cc +++ b/impeller/entity/geometry/geometry_unittests.cc @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include "flutter/testing/testing.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/geometry/geometry_asserts.h" #include "impeller/geometry/path_builder.h" +#include "impeller/renderer/testing/mocks.h" inline ::testing::AssertionResult SolidVerticesNear( std::vector a, diff --git a/impeller/tessellator/tessellator.cc b/impeller/tessellator/tessellator.cc index 8f5edc61374d5..665a6248217cb 100644 --- a/impeller/tessellator/tessellator.cc +++ b/impeller/tessellator/tessellator.cc @@ -179,6 +179,7 @@ Path::Polyline Tessellator::CreateTempPolyline(const Path& path, std::vector Tessellator::TessellateConvex(const Path& path, Scalar tolerance) { FML_DCHECK(point_buffer_); + std::vector output; point_buffer_->clear(); auto polyline = From 00b0905afc9018149e8e7dddd9aa2aaffbcda48d Mon Sep 17 00:00:00 2001 From: maRci002 Date: Thu, 28 Mar 2024 00:45:47 +0100 Subject: [PATCH 3/7] Platform channel for predictive back in route transitions on android (#49093) Support for Android's predictive back feature on internal Flutter routes. Reports predictive back gestures to the framework (where supported by the system). --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/android/BUILD.gn | 1 + .../embedding/android/FlutterActivity.java | 85 ++++++++++-- .../FlutterActivityAndFragmentDelegate.java | 99 +++++++++++++ .../embedding/engine/FlutterEngine.java | 9 ++ .../systemchannels/BackGestureChannel.java | 131 ++++++++++++++++++ .../android/io/flutter/view/FlutterView.java | 28 ++++ ...lutterActivityAndFragmentDelegateTest.java | 70 ++++++++++ .../android/FlutterActivityTest.java | 109 ++++++++++++++- 9 files changed, 519 insertions(+), 15 deletions(-) create mode 100644 shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b6d82a2305b12..feb7ecc75b01c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -40968,6 +40968,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/rend ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/RenderSurface.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/SurfaceTextureWrapper.java + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/DeferredComponentChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyboardChannel.java + ../../../flutter/LICENSE @@ -43854,6 +43855,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/render FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/SurfaceTextureSurfaceProducer.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/SurfaceTextureWrapper.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/DeferredComponentChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyboardChannel.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 3025fabbbbbec..b1a0f428e860b 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -271,6 +271,7 @@ android_java_sources = [ "io/flutter/embedding/engine/renderer/SurfaceTextureSurfaceProducer.java", "io/flutter/embedding/engine/renderer/SurfaceTextureWrapper.java", "io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java", + "io/flutter/embedding/engine/systemchannels/BackGestureChannel.java", "io/flutter/embedding/engine/systemchannels/DeferredComponentChannel.java", "io/flutter/embedding/engine/systemchannels/KeyEventChannel.java", "io/flutter/embedding/engine/systemchannels/KeyboardChannel.java", diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index dcecd3fbc1bd2..d536fed70dd06 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -22,6 +22,7 @@ import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.INITIAL_ROUTE_META_DATA_KEY; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.NORMAL_THEME_META_DATA_KEY; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -35,10 +36,13 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; +import android.window.BackEvent; +import android.window.OnBackAnimationCallback; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; @@ -678,18 +682,43 @@ public void unregisterOnBackInvokedCallback() { } private final OnBackInvokedCallback onBackInvokedCallback = - Build.VERSION.SDK_INT >= API_LEVELS.API_33 - ? new OnBackInvokedCallback() { - // TODO(garyq): Remove SuppressWarnings annotation. This was added to workaround - // a google3 bug where the linter is not properly running against API 33, causing - // a failure here. See b/243609613 and https://github.com/flutter/flutter/issues/111295 - @SuppressWarnings("Override") - @Override - public void onBackInvoked() { - onBackPressed(); - } - } - : null; + Build.VERSION.SDK_INT < API_LEVELS.API_33 ? null : createOnBackInvokedCallback(); + + @VisibleForTesting + protected OnBackInvokedCallback getOnBackInvokedCallback() { + return onBackInvokedCallback; + } + + @NonNull + @TargetApi(API_LEVELS.API_33) + @RequiresApi(API_LEVELS.API_33) + private OnBackInvokedCallback createOnBackInvokedCallback() { + if (Build.VERSION.SDK_INT >= API_LEVELS.API_34) { + return new OnBackAnimationCallback() { + @Override + public void onBackInvoked() { + commitBackGesture(); + } + + @Override + public void onBackCancelled() { + cancelBackGesture(); + } + + @Override + public void onBackProgressed(@NonNull BackEvent backEvent) { + updateBackGestureProgress(backEvent); + } + + @Override + public void onBackStarted(@NonNull BackEvent backEvent) { + startBackGesture(backEvent); + } + }; + } + + return this::onBackPressed; + } @Override public void setFrameworkHandlesBack(boolean frameworkHandlesBack) { @@ -899,6 +928,38 @@ public void onBackPressed() { } } + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void startBackGesture(@NonNull BackEvent backEvent) { + if (stillAttachedForEvent("startBackGesture")) { + delegate.startBackGesture(backEvent); + } + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void updateBackGestureProgress(@NonNull BackEvent backEvent) { + if (stillAttachedForEvent("updateBackGestureProgress")) { + delegate.updateBackGestureProgress(backEvent); + } + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void commitBackGesture() { + if (stillAttachedForEvent("commitBackGesture")) { + delegate.commitBackGesture(); + } + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void cancelBackGesture() { + if (stillAttachedForEvent("cancelBackGesture")) { + delegate.cancelBackGesture(); + } + } + @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 6b8b0c44aafde..2f1156704b982 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -7,6 +7,7 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -16,10 +17,14 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnPreDrawListener; +import android.window.BackEvent; +import android.window.OnBackAnimationCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; +import io.flutter.Build.API_LEVELS; import io.flutter.FlutterInjector; import io.flutter.Log; import io.flutter.embedding.engine.FlutterEngine; @@ -779,6 +784,100 @@ void onBackPressed() { } } + /** + * Invoke this from {@link OnBackAnimationCallback#onBackStarted(BackEvent)}. + * + *

This method should be called when the back gesture is initiated. It should be invoked as + * part of the implementation of {@link OnBackAnimationCallback}. + * + *

This method delegates the handling of the start of a back gesture to the Flutter framework, + * which is responsible for the appropriate response, such as initiating animations or preparing + * the UI for the back navigation process. + * + * @param backEvent The BackEvent object containing information about the touch. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + void startBackGesture(@NonNull BackEvent backEvent) { + ensureAlive(); + if (flutterEngine != null) { + Log.v(TAG, "Forwarding startBackGesture() to FlutterEngine."); + flutterEngine.getBackGestureChannel().startBackGesture(backEvent); + } else { + Log.w(TAG, "Invoked startBackGesture() before FlutterFragment was attached to an Activity."); + } + } + + /** + * Invoke this from {@link OnBackAnimationCallback#onBackProgressed(BackEvent)}. + * + *

This method should be called in response to progress in a back gesture, as part of the + * implementation of {@link OnBackAnimationCallback}. + * + *

This method delegates to the Flutter framework to update UI elements or animations based on + * the progression of the back gesture. + * + * @param backEvent An BackEvent object describing the progress event. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + void updateBackGestureProgress(@NonNull BackEvent backEvent) { + ensureAlive(); + if (flutterEngine != null) { + Log.v(TAG, "Forwarding updateBackGestureProgress() to FlutterEngine."); + flutterEngine.getBackGestureChannel().updateBackGestureProgress(backEvent); + } else { + Log.w( + TAG, + "Invoked updateBackGestureProgress() before FlutterFragment was attached to an Activity."); + } + } + + /** + * Invoke this from {@link OnBackAnimationCallback#onBackInvoked()}. + * + *

This method is called to signify the completion of a back gesture and commits the navigation + * action initiated by the gesture. It should be invoked as the final step in handling a back + * gesture. + * + *

This method indicates to the Flutter framework that it should proceed with the back + * navigation, including finalizing animations and updating the UI to reflect the navigation + * outcome. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + void commitBackGesture() { + ensureAlive(); + if (flutterEngine != null) { + Log.v(TAG, "Forwarding commitBackGesture() to FlutterEngine."); + flutterEngine.getBackGestureChannel().commitBackGesture(); + } else { + Log.w(TAG, "Invoked commitBackGesture() before FlutterFragment was attached to an Activity."); + } + } + + /** + * Invoke this from {@link OnBackAnimationCallback#onBackCancelled()}. + * + *

This method should be called when a back gesture is cancelled or the back button is pressed. + * It informs the Flutter framework about the cancellation. + * + *

This method enables the Flutter framework to rollback any UI changes or animations initiated + * in response to the back gesture. This includes resetting UI elements to their state prior to + * the gesture's start. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + void cancelBackGesture() { + ensureAlive(); + if (flutterEngine != null) { + Log.v(TAG, "Forwarding cancelBackGesture() to FlutterEngine."); + flutterEngine.getBackGestureChannel().cancelBackGesture(); + } else { + Log.w(TAG, "Invoked cancelBackGesture() before FlutterFragment was attached to an Activity."); + } + } + /** * Invoke this from {@link android.app.Activity#onRequestPermissionsResult(int, String[], int[])} * or {@code Fragment#onRequestPermissionsResult(int, String[], int[])}. diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 7ff6830c7bba5..4c80b90a603f7 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -25,6 +25,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.embedding.engine.renderer.RenderSurface; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; +import io.flutter.embedding.engine.systemchannels.BackGestureChannel; import io.flutter.embedding.engine.systemchannels.DeferredComponentChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel; @@ -95,6 +96,7 @@ public class FlutterEngine implements ViewUtils.DisplayUpdater { @NonNull private final LocalizationChannel localizationChannel; @NonNull private final MouseCursorChannel mouseCursorChannel; @NonNull private final NavigationChannel navigationChannel; + @NonNull private final BackGestureChannel backGestureChannel; @NonNull private final RestorationChannel restorationChannel; @NonNull private final PlatformChannel platformChannel; @NonNull private final ProcessTextChannel processTextChannel; @@ -331,6 +333,7 @@ public FlutterEngine( localizationChannel = new LocalizationChannel(dartExecutor); mouseCursorChannel = new MouseCursorChannel(dartExecutor); navigationChannel = new NavigationChannel(dartExecutor); + backGestureChannel = new BackGestureChannel(dartExecutor); platformChannel = new PlatformChannel(dartExecutor); processTextChannel = new ProcessTextChannel(dartExecutor, context.getPackageManager()); restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData); @@ -541,6 +544,12 @@ public NavigationChannel getNavigationChannel() { return navigationChannel; } + /** System channel that sends back gesture commands from Android to Flutter. */ + @NonNull + public BackGestureChannel getBackGestureChannel() { + return backGestureChannel; + } + /** * System channel that sends platform-oriented requests and information to Flutter, e.g., requests * to play sounds, requests for haptics, system chrome settings, etc. diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java new file mode 100644 index 0000000000000..6fb8997d46b54 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/BackGestureChannel.java @@ -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. + +package io.flutter.embedding.engine.systemchannels; + +import android.annotation.TargetApi; +import android.window.BackEvent; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import io.flutter.Build.API_LEVELS; +import io.flutter.Log; +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.StandardMethodCodec; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * A {@link MethodChannel} for communicating back gesture events to the Flutter framework. + * + *

The BackGestureChannel facilitates communication between the platform-specific Android back + * gesture handling code and the Flutter framework. It enables the dispatch of back gesture events + * such as start, progress, commit, and cancellation from the platform to the Flutter application. + */ +public class BackGestureChannel { + private static final String TAG = "BackGestureChannel"; + + @NonNull public final MethodChannel channel; + + /** + * Constructs a BackGestureChannel. + * + * @param dartExecutor The DartExecutor used to establish communication with the Flutter + * framework. + */ + public BackGestureChannel(@NonNull DartExecutor dartExecutor) { + this.channel = + new MethodChannel(dartExecutor, "flutter/backgesture", StandardMethodCodec.INSTANCE); + channel.setMethodCallHandler(defaultHandler); + } + + // Provide a default handler that returns an empty response to any messages + // on this channel. + private final MethodChannel.MethodCallHandler defaultHandler = + new MethodChannel.MethodCallHandler() { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + result.success(null); + } + }; + + /** + * Initiates a back gesture event. + * + *

This method should be called when the back gesture is initiated by the user. + * + * @param backEvent The BackEvent object containing information about the touch. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void startBackGesture(@NonNull BackEvent backEvent) { + Log.v(TAG, "Sending message to start back gesture"); + channel.invokeMethod("startBackGesture", backEventToJsonMap(backEvent)); + } + + /** + * Updates the progress of a back gesture event. + * + *

This method should be called to update the progress of an ongoing back gesture event. + * + * @param backEvent An BackEvent object describing the progress event. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void updateBackGestureProgress(@NonNull BackEvent backEvent) { + Log.v(TAG, "Sending message to update back gesture progress"); + channel.invokeMethod("updateBackGestureProgress", backEventToJsonMap(backEvent)); + } + + /** + * Commits the back gesture event. + * + *

This method should be called to signify the completion of a back gesture event and commit + * the navigation action initiated by the gesture. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void commitBackGesture() { + Log.v(TAG, "Sending message to commit back gesture"); + channel.invokeMethod("commitBackGesture", null); + } + + /** + * Cancels the back gesture event. + * + *

This method should be called when a back gesture is cancelled or the back button is pressed. + */ + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void cancelBackGesture() { + Log.v(TAG, "Sending message to cancel back gesture"); + channel.invokeMethod("cancelBackGesture", null); + } + + /** + * Sets a method call handler for the channel. + * + * @param handler The handler to set for the channel. + */ + public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) { + channel.setMethodCallHandler(handler); + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + private Map backEventToJsonMap(@NonNull BackEvent backEvent) { + Map message = new HashMap<>(3); + final float x = backEvent.getTouchX(); + final float y = backEvent.getTouchY(); + final Object touchOffset = (Float.isNaN(x) || Float.isNaN(y)) ? null : Arrays.asList(x, y); + message.put("touchOffset", touchOffset); + message.put("progress", backEvent.getProgress()); + message.put("swipeEdge", backEvent.getSwipeEdge()); + + return message; + } +} diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 73794cd46e41f..62f2a17505174 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -38,6 +38,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.window.BackEvent; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.annotation.UiThread; @@ -49,6 +50,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.embedding.engine.renderer.SurfaceTextureWrapper; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; +import io.flutter.embedding.engine.systemchannels.BackGestureChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel; import io.flutter.embedding.engine.systemchannels.MouseCursorChannel; @@ -124,6 +126,7 @@ static final class ViewportMetrics { private final DartExecutor dartExecutor; private final FlutterRenderer flutterRenderer; private final NavigationChannel navigationChannel; + private final BackGestureChannel backGestureChannel; private final LifecycleChannel lifecycleChannel; private final LocalizationChannel localizationChannel; private final PlatformChannel platformChannel; @@ -214,6 +217,7 @@ public void surfaceDestroyed(SurfaceHolder holder) { // Create all platform channels navigationChannel = new NavigationChannel(dartExecutor); + backGestureChannel = new BackGestureChannel(dartExecutor); lifecycleChannel = new LifecycleChannel(dartExecutor); localizationChannel = new LocalizationChannel(dartExecutor); platformChannel = new PlatformChannel(dartExecutor); @@ -369,6 +373,30 @@ public void popRoute() { navigationChannel.popRoute(); } + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void startBackGesture(@NonNull BackEvent backEvent) { + backGestureChannel.startBackGesture(backEvent); + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void updateBackGestureProgress(@NonNull BackEvent backEvent) { + backGestureChannel.updateBackGestureProgress(backEvent); + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void commitBackGesture() { + backGestureChannel.commitBackGesture(); + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + public void cancelBackGesture() { + backGestureChannel.cancelBackGesture(); + } + private void sendUserPlatformSettingsToDart() { // Lookup the current brightness of the Android OS. boolean isNightModeOn = diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 26a0a04098649..7262eaf0c37a3 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.net.Uri; import android.view.View; +import android.window.BackEvent; import androidx.annotation.NonNull; import androidx.lifecycle.Lifecycle; import androidx.test.core.app.ApplicationProvider; @@ -39,6 +40,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; +import io.flutter.embedding.engine.systemchannels.BackGestureChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel; import io.flutter.embedding.engine.systemchannels.MouseCursorChannel; @@ -671,6 +673,73 @@ public void itSendsPopRouteMessageToFlutterWhenHardwareBackButtonIsPressed() { verify(mockFlutterEngine.getNavigationChannel(), times(1)).popRoute(); } + @Test + public void itForwardsStartBackGestureToFlutter() { + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + // The FlutterEngine is set up in onAttach(). + delegate.onAttach(ctx); + + // Emulate the host and inform our delegate of the start back gesture with a mocked BackEvent + BackEvent backEvent = mock(BackEvent.class); + delegate.startBackGesture(backEvent); + + // Verify that the back gesture tried to send a message to Flutter. + verify(mockFlutterEngine.getBackGestureChannel(), times(1)).startBackGesture(backEvent); + } + + @Test + public void itForwardsUpdateBackGestureProgressToFlutter() { + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + // The FlutterEngine is set up in onAttach(). + delegate.onAttach(ctx); + + // Emulate the host and inform our delegate of the back gesture progress with a mocked BackEvent + BackEvent backEvent = mock(BackEvent.class); + delegate.updateBackGestureProgress(backEvent); + + // Verify that the back gesture tried to send a message to Flutter. + verify(mockFlutterEngine.getBackGestureChannel(), times(1)) + .updateBackGestureProgress(backEvent); + } + + @Test + public void itForwardsCommitBackGestureToFlutter() { + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + // The FlutterEngine is set up in onAttach(). + delegate.onAttach(ctx); + + // Emulate the host and inform our delegate when the back gesture is committed + delegate.commitBackGesture(); + + // Verify that the back gesture tried to send a message to Flutter. + verify(mockFlutterEngine.getBackGestureChannel(), times(1)).commitBackGesture(); + } + + @Test + public void itForwardsCancelBackGestureToFlutter() { + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + // The FlutterEngine is set up in onAttach(). + delegate.onAttach(ctx); + + // Emulate the host and inform our delegate of the back gesture cancellation + delegate.cancelBackGesture(); + + // Verify that the back gesture tried to send a message to Flutter. + verify(mockFlutterEngine.getBackGestureChannel(), times(1)).cancelBackGesture(); + } + @Test public void itForwardsOnRequestPermissionsResultToFlutterEngine() { // Create the real object that we're testing. @@ -1396,6 +1465,7 @@ private FlutterEngine mockFlutterEngine() { when(engine.getLocalizationPlugin()).thenReturn(mock(LocalizationPlugin.class)); when(engine.getMouseCursorChannel()).thenReturn(mock(MouseCursorChannel.class)); when(engine.getNavigationChannel()).thenReturn(mock(NavigationChannel.class)); + when(engine.getBackGestureChannel()).thenReturn(mock(BackGestureChannel.class)); when(engine.getPlatformViewsController()).thenReturn(mock(PlatformViewsController.class)); FlutterRenderer renderer = mock(FlutterRenderer.class); diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java index d68564f2e2aa8..f660e32ebabdf 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java @@ -22,8 +22,12 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; +import android.window.BackEvent; +import android.window.OnBackAnimationCallback; +import android.window.OnBackInvokedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import androidx.test.core.app.ApplicationProvider; @@ -122,6 +126,71 @@ public void itUnregistersOnBackInvokedCallbackOnRelease() { verify(activity, times(1)).unregisterOnBackInvokedCallback(); } + @Test + @Config(sdk = API_LEVELS.API_32) + public void onBackInvokedCallbackIsNullForSdk32OrLower() { + Intent intent = FlutterActivity.createDefaultIntent(ctx); + ActivityController activityController = + Robolectric.buildActivity(FlutterActivity.class, intent); + FlutterActivity flutterActivity = activityController.get(); + + assertNull( + "onBackInvokedCallback should be null for SDK 32 or lower", + flutterActivity.getOnBackInvokedCallback()); + } + + @Test + @Config(sdk = API_LEVELS.API_33) + @TargetApi(API_LEVELS.API_33) + public void onBackInvokedCallbackCallsOnBackPressedForSdk33() { + Intent intent = FlutterActivityWithMockBackInvokedHandling.createDefaultIntent(ctx); + ActivityController activityController = + Robolectric.buildActivity(FlutterActivityWithMockBackInvokedHandling.class, intent); + FlutterActivityWithMockBackInvokedHandling activity = activityController.get(); + + OnBackInvokedCallback callback = activity.getOnBackInvokedCallback(); + assertNotNull("onBackInvokedCallback should not be null for SDK 33", callback); + + callback.onBackInvoked(); + assertEquals("Expected onBackPressed to be called 1 times", 1, activity.onBackPressedCounter); + } + + @Test + @Config(sdk = API_LEVELS.API_34) + @TargetApi(API_LEVELS.API_34) + public void itHandlesOnBackAnimationCallbackAsExpectedForSdk34OrHigher() { + Intent intent = FlutterActivityWithMockBackInvokedHandling.createDefaultIntent(ctx); + ActivityController activityController = + Robolectric.buildActivity(FlutterActivityWithMockBackInvokedHandling.class, intent); + FlutterActivityWithMockBackInvokedHandling activity = activityController.get(); + + assertTrue( + "onBackInvokedCallback should be an instance of OnBackAnimationCallback for SDK 34 or higher", + activity.getOnBackInvokedCallback() instanceof OnBackAnimationCallback); + + OnBackAnimationCallback callback = + (OnBackAnimationCallback) activity.getOnBackInvokedCallback(); + + BackEvent mockBackEvent = mock(BackEvent.class); + callback.onBackStarted(mockBackEvent); + assertEquals( + "Expected startBackGesture to be called 1 times", 1, activity.startBackGestureCounter); + + callback.onBackProgressed(mockBackEvent); + assertEquals( + "Expected updateBackGestureProgress to be called 1 times", + 1, + activity.updateBackGestureProgressCounter); + + callback.onBackInvoked(); + assertEquals( + "Expected commitBackGesture to be called 1 times", 1, activity.commitBackGestureCounter); + + callback.onBackCancelled(); + assertEquals( + "Expected cancelBackGesture to be called 1 times", 1, activity.cancelBackGestureCounter); + } + @Test public void itCreatesDefaultIntentWithExpectedDefaults() { Intent intent = FlutterActivity.createDefaultIntent(ctx); @@ -568,12 +637,46 @@ public void resetFullyDrawn() { } } - private class FlutterActivityWithMockBackInvokedHandling extends FlutterActivity { + private static class FlutterActivityWithMockBackInvokedHandling extends FlutterActivity { + + int onBackPressedCounter = 0; + int startBackGestureCounter = 0; + int updateBackGestureProgressCounter = 0; + int commitBackGestureCounter = 0; + int cancelBackGestureCounter = 0; + + @Override + public void onBackPressed() { + onBackPressedCounter++; + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) @Override - public void registerOnBackInvokedCallback() {} + public void startBackGesture(@NonNull BackEvent backEvent) { + startBackGestureCounter++; + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + @Override + public void updateBackGestureProgress(@NonNull BackEvent backEvent) { + updateBackGestureProgressCounter++; + } + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) @Override - public void unregisterOnBackInvokedCallback() {} + public void commitBackGesture() { + commitBackGestureCounter++; + } + + @TargetApi(API_LEVELS.API_34) + @RequiresApi(API_LEVELS.API_34) + @Override + public void cancelBackGesture() { + cancelBackGestureCounter++; + } } private static final class FakeFlutterPlugin From 467b801fa6e5873da9250c2af981efe96842931c Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:48:24 -0700 Subject: [PATCH 4/7] [Impeller] adds a `plus` advanced blend for f16 pixel formats (#51589) fixes https://github.com/flutter/flutter/issues/142549 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- 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 | 21 +- .../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 + 30 files changed, 364 insertions(+), 179 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 7dc1c2a5e31bf..c48a8bfc36206 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1101,6 +1101,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..7941f9f7a9b6a 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; @@ -583,6 +586,7 @@ void BlendFilterContents::SetBlendMode(BlendMode blend_mode) { BLEND_CASE(Hue) BLEND_CASE(Saturation) BLEND_CASE(Color) + BLEND_CASE(PlusAdvanced) BLEND_CASE(Luminosity) default: FML_UNREACHABLE(); @@ -611,19 +615,26 @@ 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_, + return advanced_blend_proc_(inputs, renderer, entity, coverage, blend_mode, foreground_color_, GetAbsorbOpacity(), GetAlpha()); } 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 c128dd06e9747..a3664ed816cb9 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -941,6 +941,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 aae87f0f42e8c..9c13bcb384302 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 918bf19cd85bc55449203df3444ac8d0a21c40ae Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 27 Mar 2024 17:42:48 -0700 Subject: [PATCH 5/7] [Impeller] Reland: Use the scissor to limit all draws by clip coverage. (#51731) Reland https://github.com/flutter/engine/pull/51698. This reverts commit https://github.com/flutter/engine/commit/73c145c9ac3a3d7ea7b644e696b0ea4306ec849f. Attempts to improve https://github.com/flutter/flutter/issues/145274. Our new clipping technique paints walls on the depth buffer "in front" of the Entities that will be affected by said clips. So when an intersect clip is drawn (the common case), the clip will cover the whole framebuffer. Depth is divvied up such that deeper clips get drawn _behind_ shallower clips, and so many clips actually don't end up drawing depth across the whole framebuffer. However, if the app does a lot of transitioning from a huge clips to a small clips, a lot of unnecessary depth churn occurs (very common in Flutter -- this happens with both the app bar and floating action button in the counter template, for example). Since progressively deeper layers in the clip coverage stack always subset their parent layers, we can reduce waste for small intersect clips by setting the scissor to the clip coverage rect instead of drawing the clip to the whole screen. Note that this change _does not_ help much with huge/fullscreen clips. Also, we could potentially improve this further by computing much stricter bounds. Rather than just using clip coverage for the scissor, we could intersect it with the union of all draws affected by the clip at the cost of a bit more CPU churn per draw. I don't think that's enough juice for the squeeze though. Before (`Play/AiksTest.CanRenderNestedClips/Metal`): https://github.com/flutter/engine/assets/919017/7858400f-793a-4f7b-a0e4-fa3581198beb After (`Play/AiksTest.CanRenderNestedClips/Metal`): https://github.com/flutter/engine/assets/919017/b2f7c96d-a820-454d-91df-f5fae4976e91 --- impeller/aiks/aiks_unittests.cc | 31 ++++++++++ impeller/entity/entity_pass.cc | 61 ++++++++++++++----- impeller/entity/entity_pass_clip_stack.cc | 37 +++++++----- impeller/entity/entity_pass_clip_stack.h | 35 ++++++++--- impeller/entity/entity_pass_unittests.cc | 71 +++++++++++++++-------- testing/impeller_golden_tests_output.txt | 3 + 6 files changed, 177 insertions(+), 61 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index c48a8bfc36206..39ad0e7fed709 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -30,6 +30,7 @@ #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" #include "impeller/geometry/rect.h" +#include "impeller/geometry/size.h" #include "impeller/playground/widgets.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/snapshot.h" @@ -3497,6 +3498,36 @@ TEST_P(AiksTest, CanDrawPerspectiveTransformWithClips) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(AiksTest, CanRenderClippedBackdropFilter) { + Canvas canvas; + Paint paint; + + canvas.Scale(GetContentScale()); + + // Draw something interesting in the background. + 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.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {100, 100}, std::move(colors), std::move(stops), + Entity::TileMode::kRepeat, {}); + canvas.DrawPaint(paint); + + Rect clip_rect = Rect::MakeLTRB(50, 50, 400, 300); + + // Draw a clipped SaveLayer, where the clip coverage and SaveLayer size are + // the same. + canvas.ClipRRect(clip_rect, Size(100, 100), + Entity::ClipOperation::kIntersect); + canvas.SaveLayer({}, clip_rect, + ImageFilter::MakeFromColorFilter(*ColorFilter::MakeBlend( + BlendMode::kExclusion, Color::Red()))); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index a3664ed816cb9..89016da4e5209 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -25,6 +25,7 @@ #include "impeller/entity/inline_pass_context.h" #include "impeller/geometry/color.h" #include "impeller/geometry/rect.h" +#include "impeller/geometry/size.h" #include "impeller/renderer/command_buffer.h" #ifdef IMPELLER_DEBUG @@ -752,6 +753,25 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( FML_UNREACHABLE(); } +static void SetClipScissor(std::optional clip_coverage, + RenderPass& pass, + Point global_pass_position) { + if constexpr (!ContentContext::kEnableStencilThenCover) { + return; + } + // Set the scissor to the clip coverage area. We do this prior to rendering + // the clip itself and all its contents. + IRect scissor; + if (clip_coverage.has_value()) { + clip_coverage = clip_coverage->Shift(-global_pass_position); + scissor = IRect::RoundOut(clip_coverage.value()); + // The scissor rect must not exceed the size of the render target. + scissor = scissor.Intersection(IRect::MakeSize(pass.GetRenderTargetSize())) + .value_or(IRect()); + } + pass.SetScissor(scissor); +} + bool EntityPass::RenderElement(Entity& element_entity, size_t clip_depth_floor, InlinePassContext& pass_context, @@ -767,17 +787,6 @@ bool EntityPass::RenderElement(Entity& element_entity, return false; } - if (result.just_created) { - // Restore any clips that were recorded before the backdrop filter was - // applied. - auto& replay_entities = clip_coverage_stack.GetReplayEntities(); - for (const auto& entity : replay_entities) { - if (!entity.Render(renderer, *result.pass)) { - VALIDATION_LOG << "Failed to render entity for clip restore."; - } - } - } - // If the pass context returns a backdrop texture, we need to draw it to the // current pass. We do this because it's faster and takes significantly less // memory than storing/loading large MSAA textures. Also, it's not possible to @@ -801,6 +810,19 @@ bool EntityPass::RenderElement(Entity& element_entity, } } + if (result.just_created) { + // Restore any clips that were recorded before the backdrop filter was + // applied. + auto& replay_entities = clip_coverage_stack.GetReplayEntities(); + for (const auto& replay : replay_entities) { + SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass, + global_pass_position); + if (!replay.entity.Render(renderer, *result.pass)) { + VALIDATION_LOG << "Failed to render entity for clip restore."; + } + } + } + auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage(); if (current_clip_coverage.has_value()) { // Entity transforms are relative to the current pass position, so we need @@ -826,11 +848,18 @@ bool EntityPass::RenderElement(Entity& element_entity, element_entity.GetContents()->SetCoverageHint( Rect::Intersection(element_coverage_hint, current_clip_coverage)); - if (!clip_coverage_stack.AppendClipCoverage(clip_coverage, element_entity, - clip_depth_floor, - global_pass_position)) { - // If the entity's coverage change did not change the clip coverage, we - // don't need to render it. + EntityPassClipStack::ClipStateResult clip_state_result = + clip_coverage_stack.ApplyClipState(clip_coverage, element_entity, + clip_depth_floor, + global_pass_position); + + if (clip_state_result.clip_did_change) { + // We only need to update the pass scissor if the clip state has changed. + SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass, + global_pass_position); + } + + if (!clip_state_result.should_render) { return true; } diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index 5d126acdcbc94..67bb02d8e8f4d 100644 --- a/impeller/entity/entity_pass_clip_stack.cc +++ b/impeller/entity/entity_pass_clip_stack.cc @@ -49,20 +49,23 @@ EntityPassClipStack::GetClipCoverageLayers() const { return subpass_state_.back().clip_coverage; } -bool EntityPassClipStack::AppendClipCoverage( - Contents::ClipCoverage clip_coverage, +EntityPassClipStack::ClipStateResult EntityPassClipStack::ApplyClipState( + Contents::ClipCoverage global_clip_coverage, Entity& entity, size_t clip_depth_floor, Point global_pass_position) { + ClipStateResult result = {.should_render = false, .clip_did_change = false}; + auto& subpass_state = GetCurrentSubpassState(); - switch (clip_coverage.type) { + switch (global_clip_coverage.type) { case Contents::ClipCoverage::Type::kNoChange: break; case Contents::ClipCoverage::Type::kAppend: { auto op = CurrentClipCoverage(); subpass_state.clip_coverage.push_back( - ClipCoverageLayer{.coverage = clip_coverage.coverage, + ClipCoverageLayer{.coverage = global_clip_coverage.coverage, .clip_depth = entity.GetClipDepth() + 1}); + result.clip_did_change = true; FML_DCHECK(subpass_state.clip_coverage.back().clip_depth == subpass_state.clip_coverage.front().clip_depth + @@ -71,14 +74,14 @@ bool EntityPassClipStack::AppendClipCoverage( if (!op.has_value()) { // Running this append op won't impact the clip buffer because the // whole screen is already being clipped, so skip it. - return false; + return result; } } break; case Contents::ClipCoverage::Type::kRestore: { if (subpass_state.clip_coverage.back().clip_depth <= entity.GetClipDepth()) { // Drop clip restores that will do nothing. - return false; + return result; } auto restoration_index = entity.GetClipDepth() - @@ -96,18 +99,19 @@ bool EntityPassClipStack::AppendClipCoverage( restore_coverage = restore_coverage->Shift(-global_pass_position); } subpass_state.clip_coverage.resize(restoration_index + 1); + result.clip_did_change = true; if constexpr (ContentContext::kEnableStencilThenCover) { // Skip all clip restores when stencil-then-cover is enabled. if (subpass_state.clip_coverage.back().coverage.has_value()) { - RecordEntity(entity, clip_coverage.type); + RecordEntity(entity, global_clip_coverage.type, Rect()); } - return false; + return result; } if (!subpass_state.clip_coverage.back().coverage.has_value()) { // Running this restore op won't make anything renderable, so skip it. - return false; + return result; } auto restore_contents = @@ -130,19 +134,23 @@ bool EntityPassClipStack::AppendClipCoverage( #endif entity.SetClipDepth(entity.GetClipDepth() - clip_depth_floor); - RecordEntity(entity, clip_coverage.type); + RecordEntity(entity, global_clip_coverage.type, + subpass_state.clip_coverage.back().coverage); - return true; + result.should_render = true; + return result; } void EntityPassClipStack::RecordEntity(const Entity& entity, - Contents::ClipCoverage::Type type) { + Contents::ClipCoverage::Type type, + std::optional clip_coverage) { auto& subpass_state = GetCurrentSubpassState(); switch (type) { case Contents::ClipCoverage::Type::kNoChange: return; case Contents::ClipCoverage::Type::kAppend: - subpass_state.rendered_clip_entities.push_back(entity.Clone()); + subpass_state.rendered_clip_entities.push_back( + {.entity = entity.Clone(), .clip_coverage = clip_coverage}); break; case Contents::ClipCoverage::Type::kRestore: if (!subpass_state.rendered_clip_entities.empty()) { @@ -157,7 +165,8 @@ EntityPassClipStack::GetCurrentSubpassState() { return subpass_state_.back(); } -const std::vector& EntityPassClipStack::GetReplayEntities() const { +const std::vector& +EntityPassClipStack::GetReplayEntities() const { return subpass_state_.back().rendered_clip_entities; } diff --git a/impeller/entity/entity_pass_clip_stack.h b/impeller/entity/entity_pass_clip_stack.h index bfd7f5ba83b8e..d5181d86b9907 100644 --- a/impeller/entity/entity_pass_clip_stack.h +++ b/impeller/entity/entity_pass_clip_stack.h @@ -6,6 +6,8 @@ #define FLUTTER_IMPELLER_ENTITY_ENTITY_PASS_CLIP_STACK_H_ #include "impeller/entity/contents/contents.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/rect.h" namespace impeller { @@ -21,6 +23,20 @@ struct ClipCoverageLayer { /// stencil buffer is left in an identical state. class EntityPassClipStack { public: + struct ReplayResult { + Entity entity; + std::optional clip_coverage; + }; + + struct ClipStateResult { + /// Whether or not the Entity should be rendered. If false, the Entity may + /// be safely skipped. + bool should_render = false; + /// Whether or not the current clip coverage changed during the call to + /// `ApplyClipState`. + bool clip_did_change = false; + }; + /// Create a new [EntityPassClipStack] with an initialized coverage rect. explicit EntityPassClipStack(const Rect& initial_coverage_rect); @@ -34,24 +50,27 @@ class EntityPassClipStack { bool HasCoverage() const; - /// Returns true if entity should be rendered. - bool AppendClipCoverage(Contents::ClipCoverage clip_coverage, - Entity& entity, - size_t clip_depth_floor, - Point global_pass_position); + /// @brief Applies the current clip state to an Entity. If the given Entity + /// is a clip operation, then the clip state is updated accordingly. + ClipStateResult ApplyClipState(Contents::ClipCoverage global_clip_coverage, + Entity& entity, + size_t clip_depth_floor, + Point global_pass_position); // Visible for testing. - void RecordEntity(const Entity& entity, Contents::ClipCoverage::Type type); + void RecordEntity(const Entity& entity, + Contents::ClipCoverage::Type type, + std::optional clip_coverage); // Visible for testing. - const std::vector& GetReplayEntities() const; + const std::vector& GetReplayEntities() const; // Visible for testing. const std::vector GetClipCoverageLayers() const; private: struct SubpassState { - std::vector rendered_clip_entities; + std::vector rendered_clip_entities; std::vector clip_coverage; }; diff --git a/impeller/entity/entity_pass_unittests.cc b/impeller/entity/entity_pass_unittests.cc index ce2a66a82dc7c..137cbd2e4ad22 100644 --- a/impeller/entity/entity_pass_unittests.cc +++ b/impeller/entity/entity_pass_unittests.cc @@ -17,16 +17,26 @@ TEST(EntityPassClipStackTest, CanPushAndPopEntities) { EXPECT_TRUE(recorder.GetReplayEntities().empty()); Entity entity; - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend); + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend, + Rect::MakeLTRB(0, 0, 100, 100)); EXPECT_EQ(recorder.GetReplayEntities().size(), 1u); - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend); + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend, + Rect::MakeLTRB(0, 0, 50, 50)); EXPECT_EQ(recorder.GetReplayEntities().size(), 2u); - - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore); + ASSERT_TRUE(recorder.GetReplayEntities()[0].clip_coverage.has_value()); + ASSERT_TRUE(recorder.GetReplayEntities()[1].clip_coverage.has_value()); + // NOLINTBEGIN(bugprone-unchecked-optional-access) + EXPECT_EQ(recorder.GetReplayEntities()[0].clip_coverage.value(), + Rect::MakeLTRB(0, 0, 100, 100)); + EXPECT_EQ(recorder.GetReplayEntities()[1].clip_coverage.value(), + Rect::MakeLTRB(0, 0, 50, 50)); + // NOLINTEND(bugprone-unchecked-optional-access) + + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect()); EXPECT_EQ(recorder.GetReplayEntities().size(), 1u); - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore); + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect()); EXPECT_TRUE(recorder.GetReplayEntities().empty()); } @@ -37,7 +47,7 @@ TEST(EntityPassClipStackTest, CanPopEntitiesSafely) { EXPECT_TRUE(recorder.GetReplayEntities().empty()); Entity entity; - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore); + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect()); EXPECT_TRUE(recorder.GetReplayEntities().empty()); } @@ -48,7 +58,8 @@ TEST(EntityPassClipStackTest, CanAppendNoChange) { EXPECT_TRUE(recorder.GetReplayEntities().empty()); Entity entity; - recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kNoChange); + recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kNoChange, + Rect()); EXPECT_TRUE(recorder.GetReplayEntities().empty()); } @@ -61,12 +72,14 @@ TEST(EntityPassClipStackTest, AppendCoverageNoChange) { EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_depth, 0u); Entity entity; - recorder.AppendClipCoverage( + EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState( Contents::ClipCoverage{ .type = Contents::ClipCoverage::Type::kNoChange, .coverage = std::nullopt, }, entity, 0, Point(0, 0)); + EXPECT_TRUE(result.should_render); + EXPECT_FALSE(result.clip_did_change); EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage, Rect::MakeSize(Size::MakeWH(100, 100))); @@ -82,12 +95,14 @@ TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) { // Push a clip. Entity entity; entity.SetClipDepth(0); - recorder.AppendClipCoverage( + EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState( Contents::ClipCoverage{ .type = Contents::ClipCoverage::Type::kAppend, .coverage = Rect::MakeLTRB(50, 50, 55, 55), }, entity, 0, Point(0, 0)); + EXPECT_TRUE(result.should_render); + EXPECT_TRUE(result.clip_did_change); ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u); EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage, @@ -97,7 +112,7 @@ TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) { // Restore the clip. entity.SetClipDepth(0); - recorder.AppendClipCoverage( + recorder.ApplyClipState( Contents::ClipCoverage{ .type = Contents::ClipCoverage::Type::kRestore, .coverage = Rect::MakeLTRB(50, 50, 55, 55), @@ -120,12 +135,14 @@ TEST(EntityPassClipStackTest, UnbalancedRestore) { // Restore the clip. Entity entity; entity.SetClipDepth(0); - recorder.AppendClipCoverage( + EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState( Contents::ClipCoverage{ .type = Contents::ClipCoverage::Type::kRestore, .coverage = Rect::MakeLTRB(50, 50, 55, 55), }, entity, 0, Point(0, 0)); + EXPECT_FALSE(result.should_render); + EXPECT_FALSE(result.clip_did_change); ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u); EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage, @@ -143,12 +160,16 @@ TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) { // Push a clip. Entity entity; entity.SetClipDepth(0u); - recorder.AppendClipCoverage( - Contents::ClipCoverage{ - .type = Contents::ClipCoverage::Type::kAppend, - .coverage = Rect::MakeLTRB(50, 50, 55, 55), - }, - entity, 0, Point(0, 0)); + { + EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState( + Contents::ClipCoverage{ + .type = Contents::ClipCoverage::Type::kAppend, + .coverage = Rect::MakeLTRB(50, 50, 55, 55), + }, + entity, 0, Point(0, 0)); + EXPECT_TRUE(result.should_render); + EXPECT_TRUE(result.clip_did_change); + } ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u); EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage, @@ -163,12 +184,16 @@ TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) { Rect::MakeLTRB(50, 50, 55, 55)); entity.SetClipDepth(1); - recorder.AppendClipCoverage( - Contents::ClipCoverage{ - .type = Contents::ClipCoverage::Type::kAppend, - .coverage = Rect::MakeLTRB(54, 54, 55, 55), - }, - entity, 0, Point(0, 0)); + { + EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState( + Contents::ClipCoverage{ + .type = Contents::ClipCoverage::Type::kAppend, + .coverage = Rect::MakeLTRB(54, 54, 55, 55), + }, + entity, 0, Point(0, 0)); + EXPECT_TRUE(result.should_render); + EXPECT_TRUE(result.clip_did_change); + } EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage, Rect::MakeLTRB(54, 54, 55, 55)); diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 9c13bcb384302..ae8814380b1f8 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -161,6 +161,9 @@ impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_Vulkan.png impeller_Play_AiksTest_CanRenderBackdropBlur_Metal.png impeller_Play_AiksTest_CanRenderBackdropBlur_OpenGLES.png impeller_Play_AiksTest_CanRenderBackdropBlur_Vulkan.png +impeller_Play_AiksTest_CanRenderClippedBackdropFilter_Metal.png +impeller_Play_AiksTest_CanRenderClippedBackdropFilter_OpenGLES.png +impeller_Play_AiksTest_CanRenderClippedBackdropFilter_Vulkan.png impeller_Play_AiksTest_CanRenderClippedBlur_Metal.png impeller_Play_AiksTest_CanRenderClippedBlur_OpenGLES.png impeller_Play_AiksTest_CanRenderClippedBlur_Vulkan.png From f7dcae018bd2d5606a2a141ca910e81c4f89a3c4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 27 Mar 2024 20:49:56 -0400 Subject: [PATCH 6/7] Roll Skia from b6160ffc0b96 to 66241be7c81c (16 revisions) (#51733) https://skia.googlesource.com/skia.git/+log/b6160ffc0b96..66241be7c81c 2024-03-27 hitawala@chromium.org Add FCC, YDZDX, GBR, SMPTE240 color space support 2024-03-27 michaelludwig@google.com [graphite] Track if Device is immutable 2024-03-27 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 4f5c3553ddc3 to 29cd699ff179 (5 revisions) 2024-03-27 jvanverth@google.com Reland "[graphite] Update yuv_to_rgb_subset_effect to support Graphite." 2024-03-27 michaelludwig@google.com [graphite] Don't pass Recorder into YUVAProxies 2024-03-27 egdaniel@google.com Move some compressed data utils to shared gpu file. 2024-03-27 egdaniel@google.com Fill in VulkanCaps for compressed formats. 2024-03-27 robertphillips@google.com [graphite] Handle SkClipOp::kDifference-clipShaders in Precompilation 2024-03-27 sunnyps@chromium.org graphite: Explicitly Destroy() Dawn textures in deleteBackendTexture 2024-03-27 kjlubick@google.com Add missing SkUnicode files to public.bzl 2024-03-27 egdaniel@google.com Remove unhelpful assert in backend caps format tables. 2024-03-27 robertphillips@google.com [graphite] Add clipShaders to Precompilation system 2024-03-27 jvanverth@google.com Revert "[graphite] Update yuv_to_rgb_subset_effect to support Graphite." 2024-03-27 skia-autoroll@skia-public.iam.gserviceaccount.com Manual roll Dawn from 3de0f00ef217 to 81a2ed3a2849 (5 revisions) 2024-03-27 nicolettep@google.com [graphite] Add input attachment usage flag to renderable Vulkan texture when importing from AHardwareBuffer 2024-03-27 jvanverth@google.com [graphite] Update yuv_to_rgb_subset_effect to support Graphite. 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 | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9749cfc65353e..c75f79bb2ddc7 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': 'b6160ffc0b96908e27e6526a00313155fd76bc69', + 'skia_revision': '66241be7c81cc3308cadb4b1fba0059c9131add7', # 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 95ee697941b2c..2f564fe5bc0f0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e6c0797d1b9015dde7fab6ef78a27c0e +Signature: a4196b84c35c8d8f6a1478cf53a293f3 ==================================================================================================== LIBRARY: etc1 @@ -9527,11 +9527,14 @@ ORIGIN: ../../../flutter/third_party/skia/modules/skunicode/src/SkBidiFactory_ic ORIGIN: ../../../flutter/third_party/skia/modules/skunicode/src/SkBidiFactory_icu_subset.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/gpu/DataUtils.cpp + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/gpu/DataUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/SwizzlePriv.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/GrGLCoreFunctions.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/epoxy/GrGLMakeEpoxyEGLInterface.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlBackendSemaphore.mm + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlDirectContext.mm + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/FactoryFunctionsPriv.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/task/DrawTask.cpp + ../../../flutter/third_party/skia/LICENSE @@ -9560,11 +9563,14 @@ FILE: ../../../flutter/third_party/skia/modules/skunicode/src/SkBidiFactory_icu_ FILE: ../../../flutter/third_party/skia/modules/skunicode/src/SkBidiFactory_icu_subset.h FILE: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.cpp FILE: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.h +FILE: ../../../flutter/third_party/skia/src/gpu/DataUtils.cpp +FILE: ../../../flutter/third_party/skia/src/gpu/DataUtils.h FILE: ../../../flutter/third_party/skia/src/gpu/SwizzlePriv.h FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/GrGLCoreFunctions.h FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/gl/epoxy/GrGLMakeEpoxyEGLInterface.cpp FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlBackendSemaphore.mm FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlDirectContext.mm +FILE: ../../../flutter/third_party/skia/src/gpu/graphite/FactoryFunctionsPriv.h FILE: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.cpp FILE: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.h FILE: ../../../flutter/third_party/skia/src/gpu/graphite/task/DrawTask.cpp From 922c7b133bc2866e95d57c339ed1b64eb9ce5c57 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 27 Mar 2024 21:20:55 -0400 Subject: [PATCH 7/7] Roll Fuchsia Linux SDK from Lk8KBU-c97ROj-YHm... to uzI3wnbEGlZ_dtO0Z... (#51737) 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 | 398 ++++++++++++++-------------- 2 files changed, 200 insertions(+), 200 deletions(-) diff --git a/DEPS b/DEPS index c75f79bb2ddc7..aed7a441e7fd2 100644 --- a/DEPS +++ b/DEPS @@ -1015,7 +1015,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'Lk8KBU-c97ROj-YHm9ullKyYpp1_-GEBXGVm0jPVIOQC' + 'version': 'uzI3wnbEGlZ_dtO0Zp5QFLl5WbvXoUiKu_gjI3PhSykC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 66f32f8f7e670..3d6812f74af6d 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 63f0e714749e50dac7d3d745deea2e77 +Signature: ed807d849045c39a1539be23d04d0e93 ==================================================================================================== LIBRARY: fuchsia_sdk @@ -4358,72 +4358,72 @@ FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libm.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libpthread.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/librt.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libzircon.so -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/package_manifest.json FILE: ../../../fuchsia/sdk/linux/pkg/async-default/async-default.ifs FILE: ../../../fuchsia/sdk/linux/pkg/backend_fuchsia_globals/backend_fuchsia_globals.ifs FILE: ../../../fuchsia/sdk/linux/pkg/driver_runtime_shared_lib/driver_runtime.ifs @@ -11503,72 +11503,72 @@ FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libm.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libpthread.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/librt.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libzircon.so -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/package_manifest.json FILE: ../../../fuchsia/sdk/linux/pkg/async-default/async-default.ifs FILE: ../../../fuchsia/sdk/linux/pkg/backend_fuchsia_globals/backend_fuchsia_globals.ifs FILE: ../../../fuchsia/sdk/linux/pkg/driver_runtime_shared_lib/driver_runtime.ifs @@ -18883,72 +18883,72 @@ FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libm.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libpthread.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/librt.so FILE: ../../../fuchsia/sdk/linux/obj/x64-api-19/sysroot/lib/libzircon.so -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api16/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api17/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api18/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api19/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-1/release/package_manifest.json -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/content_checklist_path -FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/heapdump-collector/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-16/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-17/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-18/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/magma_conformance_tests/x64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/realm_builder_server/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/arm64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/riscv64-api-19/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api--1/release/package_manifest.json +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/content_checklist_path +FILE: ../../../fuchsia/sdk/linux/packages/vkreadback_test/x64-api-19/release/package_manifest.json FILE: ../../../fuchsia/sdk/linux/pkg/async-default/async-default.ifs FILE: ../../../fuchsia/sdk/linux/pkg/backend_fuchsia_globals/backend_fuchsia_globals.ifs FILE: ../../../fuchsia/sdk/linux/pkg/driver_runtime_shared_lib/driver_runtime.ifs