From bf5f133f5f71e283cbe44b4ca7702e6295eb254b Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 18:13:42 +0000 Subject: [PATCH 1/6] Add Dart AOT integration test --- .ci.yaml | 33 ++++- .github/workflows/scorecards-analysis.yml | 4 +- DEPS | 24 ++-- ci/builders/mac_host_engine.json | 9 +- ci/licenses_golden/licenses_skia | 31 ++--- ci/licenses_golden/licenses_third_party | 23 +++- flow/layers/layer.h | 6 +- flutter_frontend_server/bin/starter.dart | 1 - flutter_frontend_server/lib/server.dart | 7 +- flutter_frontend_server/pubspec.yaml | 2 +- .../compiler/shader_lib/impeller/color.glsl | 8 ++ .../display_list/display_list_dispatcher.cc | 44 +++++-- .../display_list/display_list_unittests.cc | 65 ++++++++++ impeller/entity/contents/clip_contents.cc | 2 +- impeller/entity/contents/content_context.cc | 12 +- impeller/entity/contents/content_context.h | 5 + .../entity/contents/gradient_generator.cc | 18 ++- .../contents/linear_gradient_contents.cc | 1 + .../contents/radial_gradient_contents.cc | 1 + .../entity/contents/solid_color_contents.cc | 1 + impeller/entity/contents/solid_fill_utils.h | 6 +- .../contents/sweep_gradient_contents.cc | 1 + impeller/entity/contents/text_contents.cc | 62 ++++++--- impeller/entity/contents/texture_contents.cc | 2 +- .../entity/contents/tiled_texture_contents.cc | 1 + .../entity/shaders/linear_to_srgb_filter.frag | 11 +- .../entity/shaders/srgb_to_linear_filter.frag | 11 +- impeller/fixtures/sample.comp | 10 ++ impeller/geometry/BUILD.gn | 2 + impeller/geometry/geometry_unittests.cc | 31 ++--- impeller/geometry/gradient.cc | 20 +-- impeller/geometry/gradient.h | 13 +- impeller/geometry/vector.h | 4 + impeller/renderer/allocator.cc | 4 + impeller/renderer/allocator.h | 6 + .../backend/gles/device_buffer_gles.cc | 8 ++ .../backend/gles/device_buffer_gles.h | 3 + .../renderer/backend/metal/allocator_mtl.h | 3 + .../renderer/backend/metal/allocator_mtl.mm | 5 + .../backend/metal/device_buffer_mtl.h | 8 ++ .../backend/metal/device_buffer_mtl.mm | 28 ++++ .../backend/vulkan/device_buffer_vk.cc | 4 + .../backend/vulkan/device_buffer_vk.h | 3 + impeller/renderer/buffer_view.h | 1 + impeller/renderer/compute_unittests.cc | 40 +++++- impeller/renderer/device_buffer.cc | 16 +++ impeller/renderer/device_buffer.h | 7 + impeller/renderer/host_buffer.cc | 2 +- impeller/renderer/renderer_unittests.cc | 59 +++++++++ impeller/renderer/vertex_buffer_builder.h | 20 ++- impeller/tessellator/c/tessellator.cc | 1 - impeller/tessellator/tessellator.cc | 61 +++++---- impeller/tessellator/tessellator.h | 9 ++ impeller/tessellator/tessellator_unittests.cc | 16 +++ .../backends/skia/text_render_context_skia.cc | 115 +++++++---------- lib/snapshot/BUILD.gn | 94 +++++++++----- lib/ui/geometry.dart | 21 ++- lib/ui/painting.dart | 33 +++-- lib/web_ui/dev/steps/run_tests_step.dart | 12 +- lib/web_ui/dev/test_runner.dart | 22 +++- .../src/engine/canvaskit/embedded_views.dart | 5 + .../lib/src/engine/canvaskit/layer.dart | 7 +- .../lib/src/engine/canvaskit/noto_font.dart | 29 +---- .../lib/src/engine/html/color_filter.dart | 1 + .../lib/src/engine/html/shader_mask.dart | 1 + .../lib/src/engine/pointer_binding.dart | 7 + .../test/canvaskit/embedded_views_test.dart | 16 +++ .../canvaskit/fallback_fonts_golden_test.dart | 29 ++++- lib/web_ui/test/canvaskit/layer_test.dart | 21 +++ .../test/engine/pointer_binding_test.dart | 106 +++++++++++++++- .../test/engine/surface/surface_test.dart | 63 +++++++++ shell/common/rasterizer_unittests.cc | 4 + shell/platform/android/android_egl_surface.cc | 8 -- .../macos/framework/Source/FlutterEngine.mm | 29 ++--- .../framework/Source/FlutterMetalRenderer.h | 10 -- .../framework/Source/FlutterMetalRenderer.mm | 12 +- .../Source/FlutterMetalRendererTest.mm | 4 +- .../framework/Source/FlutterOpenGLRenderer.h | 10 -- .../framework/Source/FlutterOpenGLRenderer.mm | 19 ++- .../Source/FlutterOpenGLRendererTest.mm | 4 +- .../macos/framework/Source/FlutterRenderer.h | 10 ++ .../framework/Source/FlutterViewController.mm | 2 +- .../Source/FlutterViewControllerTest.mm | 120 ++++++++++++++++++ shell/platform/fuchsia/dart_runner/BUILD.gn | 14 ++ .../fuchsia/dart_runner/tests/README.md | 37 ------ .../tests/startup_integration_test/BUILD.gn | 5 +- .../dart_aot_runner/BUILD.gn | 47 +++++++ .../dart_aot_runner/README.md | 36 ++++++ .../dart-aot-runner-integration-test.cc | 112 ++++++++++++++++ .../meta/dart-aot-runner-integration-test.cml | 40 ++++++ .../meta/gtest_runner.shard.cml | 18 +++ .../dart_echo_server/BUILD.gn | 78 ++++++++++++ .../dart_echo_server/README.md | 7 + .../main.dart | 0 .../meta/dart-aot-echo-server.cml | 21 +++ .../meta/dart-jit-echo-server.cml | 1 + .../dart_jit_runner/BUILD.gn | 7 +- .../dart_jit_runner/README.md | 35 ++++- .../dart-jit-runner-integration-test.cc | 63 ++++++++- .../dart_jit_echo_server/BUILD.gn | 45 ------- .../meta/dart-jit-runner-integration-test.cml | 9 ++ .../flatland_external_view_embedder.cc | 8 +- .../flutter/flatland_external_view_embedder.h | 1 + .../fuchsia/flutter/flatland_platform_view.cc | 10 +- ...atland_external_view_embedder_unittests.cc | 23 +++- .../tests/flatland_platform_view_unittest.cc | 10 +- shell/platform/fuchsia/unit_tests.md | 6 + sky/tools/create_macos_gen_snapshots.py | 16 +-- sky/tools/gen_snapshots.py | 46 ------- sky/tools/macos.gni | 41 ++++++ sky/tools/macos_snapshots.gni | 48 ------- sky/tools/strip_bitcode.py | 44 +++++++ testing/fuchsia/test_suites.yaml | 8 +- .../platform/ax_platform_node_win_unittest.cc | 4 +- .../ax/platform/test_ax_node_wrapper.cc | 5 + .../ax/platform/test_ax_node_wrapper.h | 3 + tools/clang_tidy/lib/clang_tidy.dart | 12 +- tools/clang_tidy/lib/src/git_repo.dart | 75 ++++++++--- tools/clang_tidy/lib/src/options.dart | 18 ++- tools/clang_tidy/test/clang_tidy_test.dart | 23 ++++ tools/fuchsia/build_fuchsia_artifacts.py | 13 +- tools/fuchsia/devshell/run_unit_tests.sh | 18 ++- .../devshell/test/test_run_unit_tests.sh | 30 +++++ web_sdk/sdk_rewriter.dart | 9 +- web_sdk/test/sdk_rewriter_test.dart | 25 ---- 125 files changed, 1982 insertions(+), 678 deletions(-) create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/BUILD.gn create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/README.md create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart-aot-runner-integration-test.cc create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/dart-aot-runner-integration-test.cml create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/gtest_runner.shard.cml create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/BUILD.gn create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md rename shell/platform/fuchsia/dart_runner/tests/startup_integration_test/{dart_jit_runner/dart_jit_echo_server => dart_echo_server}/main.dart (100%) create mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-aot-echo-server.cml rename shell/platform/fuchsia/dart_runner/tests/startup_integration_test/{dart_jit_runner/dart_jit_echo_server => dart_echo_server}/meta/dart-jit-echo-server.cml (92%) delete mode 100644 shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/BUILD.gn delete mode 100755 sky/tools/gen_snapshots.py create mode 100644 sky/tools/macos.gni delete mode 100644 sky/tools/macos_snapshots.gni create mode 100755 sky/tools/strip_bitcode.py create mode 100755 tools/fuchsia/devshell/test/test_run_unit_tests.sh diff --git a/.ci.yaml b/.ci.yaml index e1843b686261e..21989f3133d5e 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -186,11 +186,22 @@ targets: clobber: "true" timeout: 60 - - name: Linux clang-tidy + - name: Linux Host clang-tidy recipe: engine/engine_lint properties: add_recipes_cq: "true" cores: "32" + lint_android: "false" + lint_host: "true" + timeout: 60 + + - name: Linux Android clang-tidy + recipe: engine/engine_lint + properties: + add_recipes_cq: "true" + cores: "32" + lint_android: "true" + lint_host: "false" timeout: 60 - name: Linux Arm Host Engine @@ -210,11 +221,10 @@ targets: - name: Linux linux_host_engine recipe: engine_v2/engine_v2 - bringup: true timeout: 60 properties: config_name: linux_host_engine - environment: Staging + environment: Production - name: Linux linux_android_aot_engine recipe: engine_v2/engine_v2 @@ -304,11 +314,10 @@ targets: - name: Mac mac_host_engine recipe: engine_v2/engine_v2 - bringup: true timeout: 60 properties: config_name: mac_host_engine - environment: Staging + environment: Production - name: Mac Unopt recipe: engine/engine_unopt @@ -323,12 +332,24 @@ targets: xcode: 14a5294e # xcode 14.0 beta 5 timeout: 75 - - name: Mac clang-tidy + - name: Mac Host clang-tidy + recipe: engine/engine_lint + properties: + add_recipes_cq: "true" + jazzy_version: "0.14.1" + xcode: 14a5294e # xcode 14.0 beta 5 + lint_host: "true" + lint_ios: "false" + timeout: 75 + + - name: Mac iOS clang-tidy recipe: engine/engine_lint properties: add_recipes_cq: "true" jazzy_version: "0.14.1" xcode: 14a5294e # xcode 14.0 beta 5 + lint_host: "false" + lint_ios: "true" timeout: 75 - name: Mac iOS Engine diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index efb5b3cf5d8f7..6d39c442a6271 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -42,7 +42,7 @@ jobs: with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@865b4092859256271290c77adbd10a43f4779972 + uses: ossf/scorecard-action@e363bfca00e752f91de7b7d2a77340e2e523cb18 with: results_file: results.sarif results_format: sarif @@ -65,6 +65,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@86f3159a697a097a813ad9bfa0002412d97690a4 + uses: github/codeql-action/upload-sarif@e0e5ded33cabb451ae0a9768fc7b0410bad9ad44 with: sarif_file: results.sarif diff --git a/DEPS b/DEPS index ca387d1a2f68a..79be3e4abaeea 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': 'e11ad879ef49e0c7081d6fee9e3758b439077aa8', + 'skia_revision': '65505f07f072d15d925ebf1f62862ee9ac56b6ca', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -43,7 +43,7 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS. # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': 'e205126d124ca8cdc54a0d72ca43b10ab693b3f4', + 'dart_revision': '426453fdc4fbeaa62689155d58a158e8143b812f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -109,7 +109,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'b7ef254d8cec53bdad39cdb4a284af1d0a79dbdb', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '64d07cbd3d9fa0c15f06c8e24c3bdbf5a9a06329', # Fuchsia compatibility # @@ -142,7 +142,7 @@ deps = { Var('github_git') + '/google/flatbuffers.git' + '@' + '0a80646371179f8a7a5c1f42c31ee1d44dcf6709', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '3e03346162e9bdd41850a1184d2713da4add719e', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '20f8ac695af59b6c830def7d4e95bfeb13dd7be5', 'src/third_party/khronos': Var('chromium_git') + '/chromium/src/third_party/khronos.git' + '@' + '676d544d2b8f48903b7da9fceffaa534a5613978', @@ -210,7 +210,7 @@ deps = { Var('dart_git') + '/dart_style.git@49bc3ff32b5578b6e19f8fd376d668130941ee29', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@a6676ee586283d6ea0f835f0c70fc1115400964f', + Var('dart_git') + '/dartdoc.git@866338f12eb404217ec5a2e245ba5007779b7a3c', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@fb5f2667826c0900e551d19101052f84e35f41bf', @@ -225,10 +225,10 @@ deps = { Var('dart_git') + '/glob.git@1d51fcc172e5adfbae6e82c3f8f119774cb2fca2', 'src/third_party/dart/third_party/pkg/html': - Var('dart_git') + '/html.git@8243e967caad9932c13971af3b2a7c8f028383d5', + Var('dart_git') + '/html.git@faafebfd2965ce38ed8ca22e42791255d48ad5e7', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@d6a4bf1e8f9d6e8f372958387cea32b0a6a62cfa', + Var('dart_git') + '/http.git@738a55b20e391c5a526b86bf4b02af6b7745b494', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', @@ -252,10 +252,10 @@ deps = { Var('dart_git') + '/matcher.git@6a9b83bbd73e50df2058b3e8e4aa301df49569c6', 'src/third_party/dart/third_party/pkg/mime': - Var('dart_git') + '/mime.git@0a75a41445eb642674a0a271eecde78cb025ee60', + Var('dart_git') + '/mime.git@bf041aa372a27aae6f94e185aa0af3932b9de98b', 'src/third_party/dart/third_party/pkg/mockito': - Var('dart_git') + '/mockito.git@ef37e871d2673a66ca57303253901748622f04ca', + Var('dart_git') + '/mockito.git@02ad6c793d9ea970b5cc892f45a55d12d8ebf4e8', 'src/third_party/dart/third_party/pkg/oauth2': Var('dart_git') + '/oauth2.git@199ebf15cbd5b07958438184f32e41c4447a57bf', @@ -297,7 +297,7 @@ deps = { Var('dart_git') + '/stack_trace.git@17f09c2c6845bb31c7c385acecce5befb8527a13', 'src/third_party/dart/third_party/pkg/stream_channel': - Var('dart_git') + '/stream_channel.git@63831cb74c5a413da893bda0fa4a80b5cb567076', + Var('dart_git') + '/stream_channel.git@a5129ca44322a7024074ca38fb98e343dcb638c7', 'src/third_party/dart/third_party/pkg/string_scanner': Var('dart_git') + '/string_scanner.git@2d84b16d8ae03c3a8c2417b71abe0fe6de7d8bf6', @@ -315,7 +315,7 @@ deps = { Var('dart_git') + '/typed_data.git@6369490ede1c87a4a5758304a606a6e4eee364b9', 'src/third_party/dart/third_party/pkg/usage': - Var('dart_git') + '/usage.git@e287a72228974886d8a3b40ddcdf12f69d7c6a22', + Var('dart_git') + '/usage.git@9a98c89163c7122bf946954209a69718300392d9', 'src/third_party/dart/third_party/pkg/watcher': Var('dart_git') + '/watcher.git' + '@' + Var('dart_watcher_rev'), @@ -424,7 +424,7 @@ deps = { Var('fuchsia_git') + '/third_party/libjpeg-turbo' + '@' + '0fb821f3b2e570b2783a94ccd9a2fb1f4916ae9f', 'src/third_party/libpng': - Var('flutter_git') + '/third_party/libpng' + '@' + '134cf139cb24d802ee6ad5fc51bccff3221c2b49', + Var('flutter_git') + '/third_party/libpng' + '@' + '9187b6e12756317f6d44fc669ac11dfc262bd192', 'src/third_party/libwebp': Var('chromium_git') + '/webm/libwebp.git' + '@' + '7dfde712a477e420968732161539011e0fd446cf', # 1.2.0 diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index 55c8d4b16b2ba..d5288a222cda4 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -141,6 +141,7 @@ "base_path": "out/mac_debug_arm64/zip_archives/", "type": "gcs", "include_paths": [ + "out/mac_debug_arm64/zip_archives/darwin-arm64/artifacts.zip", "out/mac_debug_arm64/zip_archives/dart-sdk-darwin-arm64.zip" ], "name": "mac_debug_arm64" @@ -170,6 +171,7 @@ "targets": [ "flutter/build/archives:dart_sdk_archive", "flutter/build/archives:archive_gen_snapshot", + "flutter/build/archives:artifacts", "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" ] }, @@ -216,7 +218,9 @@ { "base_path": "out/mac_release_arm64/zip_archives/", "type": "gcs", - "include_paths": [], + "include_paths": [ + "out/mac_release_arm64/zip_archives/darwin-arm64/font-subset.zip" + ], "name": "mac_release_arm64" } ], @@ -242,7 +246,8 @@ "config": "mac_release_arm64", "targets": [ "flutter/build/archives:archive_gen_snapshot", - "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework", + "flutter/tools/font-subset" ] }, "tests": [] diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5936bae510de3..2b2ea83562a30 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d63829ecd31743a592927756ec45044f +Signature: e192a98405d9cf027fcba5e32090db50 UNUSED LICENSES: @@ -807,6 +807,7 @@ FILE: ../../../third_party/skia/infra/bots/assets/win_toolchain/VERSION FILE: ../../../third_party/skia/infra/bots/assets/xcode-11.4.1/VERSION FILE: ../../../third_party/skia/infra/bots/cfg.json FILE: ../../../third_party/skia/infra/bots/jobs.json +FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm-OptimizeForSize-Android_NoPatch.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm-Release-Android_API26.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm-Release-Android_ASAN.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm-Release-Chromebook_GLES.json @@ -1057,7 +1058,6 @@ FILE: ../../../third_party/skia/modules/canvaskit/htmlcanvas/util.js FILE: ../../../third_party/skia/modules/canvaskit/interface.js FILE: ../../../third_party/skia/modules/canvaskit/karma.bazel.js FILE: ../../../third_party/skia/modules/canvaskit/karma.conf.js -FILE: ../../../third_party/skia/modules/canvaskit/karma.google3.conf.js FILE: ../../../third_party/skia/modules/canvaskit/matrix.js FILE: ../../../third_party/skia/modules/canvaskit/memory.js FILE: ../../../third_party/skia/modules/canvaskit/package-lock.json @@ -1254,24 +1254,24 @@ FILE: ../../../third_party/skia/src/sksl/analysis/BUILD.bazel FILE: ../../../third_party/skia/src/sksl/codegen/BUILD.bazel FILE: ../../../third_party/skia/src/sksl/dsl/BUILD.bazel FILE: ../../../third_party/skia/src/sksl/dsl/priv/BUILD.bazel -FILE: ../../../third_party/skia/src/sksl/generated/sksl_compute.dehydrated.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_compute.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_frag.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_compute.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_frag.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_gpu.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_frag.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_gpu.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_frag.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_gpu.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_frag.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_vert.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_frag.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_vert.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_public.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_graphite_vert.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_public.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_rt_shader.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_public.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_rt_shader.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_shared.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_rt_shader.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_shared.minified.sksl -FILE: ../../../third_party/skia/src/sksl/generated/sksl_vert.dehydrated.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_shared.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/generated/sksl_vert.minified.sksl +FILE: ../../../third_party/skia/src/sksl/generated/sksl_vert.unoptimized.sksl FILE: ../../../third_party/skia/src/sksl/ir/BUILD.bazel FILE: ../../../third_party/skia/src/sksl/lex/BUILD.bazel FILE: ../../../third_party/skia/src/sksl/lex/sksl.lex @@ -2643,6 +2643,7 @@ FILE: ../../../third_party/skia/src/sksl/transform/SkSLEliminateDeadGlobalVariab FILE: ../../../third_party/skia/src/sksl/transform/SkSLEliminateDeadLocalVariables.cpp FILE: ../../../third_party/skia/src/sksl/transform/SkSLEliminateUnreachableCode.cpp FILE: ../../../third_party/skia/src/sksl/transform/SkSLProgramWriter.h +FILE: ../../../third_party/skia/src/sksl/transform/SkSLReplaceConstVarsWithLiterals.cpp FILE: ../../../third_party/skia/src/text/gpu/Slug.cpp FILE: ../../../third_party/skia/src/text/gpu/SubRunAllocator.cpp FILE: ../../../third_party/skia/src/text/gpu/SubRunAllocator.h @@ -4032,8 +4033,6 @@ FILE: ../../../third_party/skia/src/sksl/SkSLBuiltinMap.cpp FILE: ../../../third_party/skia/src/sksl/SkSLBuiltinMap.h FILE: ../../../third_party/skia/src/sksl/SkSLConstantFolder.cpp FILE: ../../../third_party/skia/src/sksl/SkSLConstantFolder.h -FILE: ../../../third_party/skia/src/sksl/SkSLDehydrator.cpp -FILE: ../../../third_party/skia/src/sksl/SkSLDehydrator.h FILE: ../../../third_party/skia/src/sksl/SkSLInliner.cpp FILE: ../../../third_party/skia/src/sksl/SkSLInliner.h FILE: ../../../third_party/skia/src/sksl/SkSLMemoryPool.h @@ -5563,10 +5562,13 @@ FILE: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.cpp FILE: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.h FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCaps.cpp FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCaps.h +FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCommandBuffer.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCommandBuffer.h FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanResourceProvider.cpp FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanResourceProvider.h FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanSharedContext.cpp FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanSharedContext.h +FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanUtils.h FILE: ../../../third_party/skia/src/gpu/tessellate/FixedCountBufferUtils.cpp FILE: ../../../third_party/skia/src/gpu/tessellate/FixedCountBufferUtils.h FILE: ../../../third_party/skia/src/gpu/tessellate/LinearTolerances.h @@ -5936,8 +5938,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/GrTessellationShader.h FILE: ../../../third_party/skia/src/opts/SkVM_opts.h FILE: ../../../third_party/skia/src/sksl/SkSLAnalysis.cpp FILE: ../../../third_party/skia/src/sksl/SkSLModifiersPool.h -FILE: ../../../third_party/skia/src/sksl/SkSLRehydrator.cpp -FILE: ../../../third_party/skia/src/sksl/SkSLRehydrator.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLConstructor.cpp ---------------------------------------------------------------------------------------------------- Copyright 2020 Google LLC. @@ -6566,6 +6566,7 @@ FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputeCommandEncoder.h FILE: ../../../third_party/skia/src/sfnt/SkOTTable_hmtx.h FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.h +FILE: ../../../third_party/skia/src/sksl/ir/SkSLLiteral.cpp FILE: ../../../third_party/skia/src/text/gpu/SDFMaskFilter.h FILE: ../../../third_party/skia/src/utils/SkBlitterTrace.h FILE: ../../../third_party/skia/src/utils/SkBlitterTraceCommon.h diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 5f3fac8a694b6..c9101d9dac379 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: fa51649775d7520a0f11c82403adedb1 +Signature: 8f41f1108deb09e08ffeea247e19672f UNUSED LICENSES: @@ -10866,6 +10866,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/async_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/compact_hash.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/developer.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/timeline.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/compact_hash.dart FILE: ../../../third_party/dart/sdk/lib/convert/base64.dart FILE: ../../../third_party/dart/sdk/lib/developer/developer.dart FILE: ../../../third_party/dart/sdk/lib/developer/extension.dart @@ -11269,6 +11270,10 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/string_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/timer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/type_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/weak_property.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/array_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/bool_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/integers_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/map_patch.dart FILE: ../../../third_party/dart/sdk/lib/async/async.dart FILE: ../../../third_party/dart/sdk/lib/async/async_error.dart FILE: ../../../third_party/dart/sdk/lib/async/broadcast_stream_controller.dart @@ -11508,6 +11513,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/bin/namespace_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/bin/sync_socket_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/bigint_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/class_id_fasta.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/bigint_patch.dart FILE: ../../../third_party/dart/sdk/lib/cli/cli.dart FILE: ../../../third_party/dart/sdk/lib/cli/wait_for.dart FILE: ../../../third_party/dart/sdk/lib/core/bigint.dart @@ -12361,7 +12367,9 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/symbol_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/timer_impl.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/typed_data_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/uri_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/collection_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/io_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/null_patch.dart FILE: ../../../third_party/dart/sdk/lib/async/deferred_load.dart FILE: ../../../third_party/dart/sdk/lib/async/schedule_microtask.dart FILE: ../../../third_party/dart/sdk/lib/async/stream.dart @@ -12877,10 +12885,19 @@ FILE: ../../../third_party/dart/runtime/bin/thread_absl.cc FILE: ../../../third_party/dart/runtime/bin/thread_absl.h FILE: ../../../third_party/dart/runtime/platform/mach_o.h FILE: ../../../third_party/dart/runtime/platform/pe.h +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/bin/explore.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/heapsnapshot.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/src/analysis.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/src/cli.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/src/expression.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/src/format.dart +FILE: ../../../third_party/dart/runtime/tools/heapsnapshot/lib/src/load.dart FILE: ../../../third_party/dart/runtime/vm/compiler/backend/il_serializer.cc FILE: ../../../third_party/dart/runtime/vm/compiler/backend/il_serializer.h FILE: ../../../third_party/dart/runtime/vm/heap/gc_shared.cc FILE: ../../../third_party/dart/runtime/vm/heap/gc_shared.h +FILE: ../../../third_party/dart/runtime/vm/heap/page.cc +FILE: ../../../third_party/dart/runtime/vm/heap/page.h FILE: ../../../third_party/dart/runtime/vm/instructions.cc FILE: ../../../third_party/dart/runtime/vm/malloc_hooks_riscv.cc FILE: ../../../third_party/dart/runtime/vm/os_thread_absl.cc @@ -12894,6 +12911,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/synced/embedded_ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/ffi_native_finalizer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/finalizer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/hash_factories.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/record_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/async_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/bool.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/class_id.dart @@ -12916,7 +12934,6 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/js_util_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/list.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/math_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/object_patch.dart -FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/print_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/regexp_helper.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/regexp_patch.dart @@ -13085,6 +13102,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/js_runtime/lib/synced/embedded FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/convert_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/lib_prefix.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/profiler.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/convert_patch.dart FILE: ../../../third_party/dart/sdk/lib/collection/set.dart FILE: ../../../third_party/dart/sdk/lib/core/sink.dart FILE: ../../../third_party/dart/sdk/lib/developer/profiler.dart @@ -13198,6 +13216,7 @@ LIBRARY: dart ORIGIN: ../../../third_party/dart/sdk/lib/_internal/vm/lib/bigint_patch.dart TYPE: LicenseType.mit FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/bigint_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/bigint_patch.dart ---------------------------------------------------------------------------------------------------- Copyright (c) 2003-2005 Tom Wu Copyright (c) 2012 Adam Singer (adam@solvr.io) diff --git a/flow/layers/layer.h b/flow/layers/layer.h index bb57b430fa3b0..09f47b5de4d50 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -65,10 +65,10 @@ struct PrerollContext { const float frame_device_pixel_ratio = 1.0f; // These allow us to track properties like elevation, opacity, and the - // prescence of a platform view during Preroll. + // presence of a platform view during Preroll. bool has_platform_view = false; // These allow us to track properties like elevation, opacity, and the - // prescence of a texture layer during Preroll. + // presence of a texture layer during Preroll. bool has_texture_layer = false; // This field indicates whether the subtree rooted at this layer can @@ -157,7 +157,7 @@ struct PaintContext { }; // Represents a single composited layer. Created on the UI thread but then -// subquently used on the Rasterizer thread. +// subsequently used on the Rasterizer thread. class Layer { public: Layer(); diff --git a/flutter_frontend_server/bin/starter.dart b/flutter_frontend_server/bin/starter.dart index 88101360d42cd..f78c3a2754d5c 100644 --- a/flutter_frontend_server/bin/starter.dart +++ b/flutter_frontend_server/bin/starter.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart=2.8 library frontend_server; import 'dart:io'; diff --git a/flutter_frontend_server/lib/server.dart b/flutter_frontend_server/lib/server.dart index 5b6543f9845b8..49f8ffd08d2e5 100644 --- a/flutter_frontend_server/lib/server.dart +++ b/flutter_frontend_server/lib/server.dart @@ -4,7 +4,6 @@ // ignore_for_file: avoid_print -// @dart=2.8 library flutter_frontend_server; import 'dart:async'; @@ -26,9 +25,9 @@ import 'package:path/path.dart' as path; /// version for testing. Future starter( List args, { - frontend.CompilerInterface compiler, - Stream> input, - StringSink output, + frontend.CompilerInterface? compiler, + Stream>? input, + StringSink? output, }) async { ArgResults options; try { diff --git a/flutter_frontend_server/pubspec.yaml b/flutter_frontend_server/pubspec.yaml index fc8082891bcfb..b4cbec70b3011 100644 --- a/flutter_frontend_server/pubspec.yaml +++ b/flutter_frontend_server/pubspec.yaml @@ -18,7 +18,7 @@ homepage: https://flutter.dev # relative to this directory into //third_party/dart environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: args: any diff --git a/impeller/compiler/shader_lib/impeller/color.glsl b/impeller/compiler/shader_lib/impeller/color.glsl index 0a6fb88c2b621..303b68e4c4570 100644 --- a/impeller/compiler/shader_lib/impeller/color.glsl +++ b/impeller/compiler/shader_lib/impeller/color.glsl @@ -18,4 +18,12 @@ vec4 IPUnpremultiply(vec4 color) { return vec4(color.rgb / color.a, color.a); } +/// Convert an unpremultiplied color (a color which has its color components +/// separated from its alpha value) to a premultiplied color. +/// +/// Returns (0, 0, 0, 0) if the alpha component is 0. +vec4 IPPremultiply(vec4 color) { + return vec4(color.rgb * color.a, color.a); +} + #endif diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index ad2eb4286d123..1da0db438cb8b 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -290,6 +290,30 @@ static std::vector ToRSXForms(const SkRSXform xform[], int count) { return result; } +// Convert display list colors + stops into impeller colors and stops, taking +// care to ensure that the stops always start with 0.0 and end with 1.0. +template +static void ConvertStops(T* gradient, + std::vector* colors, + std::vector* stops) { + FML_DCHECK(gradient->stop_count() >= 2); + + auto* dl_colors = gradient->colors(); + auto* dl_stops = gradient->stops(); + if (dl_stops[0] != 0.0) { + colors->emplace_back(ToColor(dl_colors[0])); + stops->emplace_back(0); + } + for (auto i = 0; i < gradient->stop_count(); i++) { + colors->emplace_back(ToColor(dl_colors[i])); + stops->emplace_back(dl_stops[i]); + } + if (stops->back() != 1.0) { + colors->emplace_back(colors->back()); + stops->emplace_back(1.0); + } +} + // |flutter::Dispatcher| void DisplayListDispatcher::setColorSource( const flutter::DlColorSource* source) { @@ -314,10 +338,8 @@ void DisplayListDispatcher::setColorSource( auto end_point = ToPoint(linear->end_point()); std::vector colors; std::vector stops; - for (auto i = 0; i < linear->stop_count(); i++) { - colors.emplace_back(ToColor(linear->colors()[i])); - stops.emplace_back(linear->stops()[i]); - } + ConvertStops(linear, &colors, &stops); + auto tile_mode = ToTileMode(linear->tile_mode()); auto matrix = ToMatrix(linear->matrix()); paint_.color_source = [start_point, end_point, colors = std::move(colors), @@ -340,10 +362,8 @@ void DisplayListDispatcher::setColorSource( auto radius = radialGradient->radius(); std::vector colors; std::vector stops; - for (auto i = 0; i < radialGradient->stop_count(); i++) { - colors.emplace_back(ToColor(radialGradient->colors()[i])); - stops.emplace_back(radialGradient->stops()[i]); - } + ConvertStops(radialGradient, &colors, &stops); + auto tile_mode = ToTileMode(radialGradient->tile_mode()); auto matrix = ToMatrix(radialGradient->matrix()); paint_.color_source = [center, radius, colors = std::move(colors), @@ -367,11 +387,9 @@ void DisplayListDispatcher::setColorSource( auto start_angle = Degrees(sweepGradient->start()); auto end_angle = Degrees(sweepGradient->end()); std::vector colors; - std::vector stops; - for (auto i = 0; i < sweepGradient->stop_count(); i++) { - colors.emplace_back(ToColor(sweepGradient->colors()[i])); - stops.emplace_back(sweepGradient->stops()[i]); - } + std::vector stops; + ConvertStops(sweepGradient, &colors, &stops); + auto tile_mode = ToTileMode(sweepGradient->tile_mode()); auto matrix = ToMatrix(sweepGradient->matrix()); paint_.color_source = [center, start_angle, end_angle, diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index f80888d2b5699..201371839b172 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -763,6 +763,20 @@ TEST_P(DisplayListTest, CanDrawWithMatrixFilter) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) { + flutter::DlPaint paint; + paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128)); + flutter::DisplayListBuilder builder; + paint.setColorFilter(flutter::DlLinearToSrgbGammaColorFilter::instance.get()); + builder.drawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint); + builder.translate(0, 200); + + paint.setColorFilter(flutter::DlSrgbToLinearGammaColorFilter::instance.get()); + builder.drawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + TEST_P(DisplayListTest, CanDrawPaintWithColorSource) { const flutter::DlColor colors[2] = { flutter::DlColor(0xFFF44336), @@ -815,5 +829,56 @@ TEST_P(DisplayListTest, CanDrawPaintWithColorSource) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanBlendDstOverAndDstCorrectly) { + flutter::DisplayListBuilder builder; + + { + builder.saveLayer(nullptr, nullptr); + builder.translate(100, 100); + flutter::DlPaint paint; + paint.setColor(flutter::DlColor::kRed()); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + paint.setColor(flutter::DlColor::kBlue().withAlpha(127)); + paint.setBlendMode(flutter::DlBlendMode::kSrcOver); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + builder.restore(); + } + { + builder.saveLayer(nullptr, nullptr); + builder.translate(300, 100); + flutter::DlPaint paint; + paint.setColor(flutter::DlColor::kBlue().withAlpha(127)); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + paint.setColor(flutter::DlColor::kRed()); + paint.setBlendMode(flutter::DlBlendMode::kDstOver); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + builder.restore(); + } + { + builder.saveLayer(nullptr, nullptr); + builder.translate(100, 300); + flutter::DlPaint paint; + paint.setColor(flutter::DlColor::kRed()); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + paint.setColor(flutter::DlColor::kBlue().withAlpha(127)); + paint.setBlendMode(flutter::DlBlendMode::kSrc); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + builder.restore(); + } + { + builder.saveLayer(nullptr, nullptr); + builder.translate(300, 300); + flutter::DlPaint paint; + paint.setColor(flutter::DlColor::kBlue().withAlpha(127)); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + paint.setColor(flutter::DlColor::kRed()); + paint.setBlendMode(flutter::DlBlendMode::kDst); + builder.drawRect(SkRect::MakeSize({200, 200}), paint); + builder.restore(); + } + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index b9928fe84d43d..1914b8335304b 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -120,7 +120,7 @@ bool ClipContents::Render(const ContentContext& renderer, cmd.pipeline = renderer.GetClipPipeline(options); cmd.BindVertices(CreateSolidFillVertices( - path_, pass.GetTransientsBuffer())); + renderer.GetTessellator(), path_, pass.GetTransientsBuffer())); info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 80e970f523323..adc57b746cc48 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -11,6 +11,7 @@ #include "impeller/renderer/formats.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" +#include "impeller/tessellator/tessellator.h" namespace impeller { @@ -43,7 +44,7 @@ void ContentContextOptions::ApplyToPipelineDescriptor( color0.src_color_blend_factor = BlendFactor::kOne; break; case BlendMode::kDestination: - color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.dst_alpha_blend_factor = BlendFactor::kOne; color0.dst_color_blend_factor = BlendFactor::kOne; color0.src_alpha_blend_factor = BlendFactor::kZero; color0.src_color_blend_factor = BlendFactor::kZero; @@ -55,7 +56,7 @@ void ContentContextOptions::ApplyToPipelineDescriptor( color0.src_color_blend_factor = BlendFactor::kOne; break; case BlendMode::kDestinationOver: - color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.dst_alpha_blend_factor = BlendFactor::kOne; color0.dst_color_blend_factor = BlendFactor::kOne; color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; @@ -142,7 +143,8 @@ static std::unique_ptr CreateDefaultPipeline( } ContentContext::ContentContext(std::shared_ptr context) - : context_(std::move(context)) { + : context_(std::move(context)), + tessellator_(std::make_shared()) { if (!context_ || !context_->IsValid()) { return; } @@ -285,6 +287,10 @@ std::shared_ptr ContentContext::MakeSubpass( return subpass_texture; } +std::shared_ptr ContentContext::GetTessellator() const { + return tessellator_; +} + std::shared_ptr ContentContext::GetContext() const { return context_; } diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 83089ad08aaac..ce96fde7721c9 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -183,6 +183,8 @@ struct ContentContextOptions { void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const; }; +class Tessellator; + class ContentContext { public: explicit ContentContext(std::shared_ptr context); @@ -191,6 +193,8 @@ class ContentContext { bool IsValid() const; + std::shared_ptr GetTessellator() const; + std::shared_ptr> GetLinearGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(linear_gradient_fill_pipelines_, opts); @@ -458,6 +462,7 @@ class ContentContext { } bool is_valid_ = false; + std::shared_ptr tessellator_; FML_DISALLOW_COPY_AND_ASSIGN(ContentContext); }; diff --git a/impeller/entity/contents/gradient_generator.cc b/impeller/entity/contents/gradient_generator.cc index bfb0afff250ee..c66afc3a9d0e1 100644 --- a/impeller/entity/contents/gradient_generator.cc +++ b/impeller/entity/contents/gradient_generator.cc @@ -19,18 +19,16 @@ std::shared_ptr CreateGradientTexture( const std::vector& colors, const std::vector& stops, std::shared_ptr context) { - // If the computed scale is nearly the same as the color length, then the - // stops are evenly spaced and we can lerp entirely in the gradient shader. - // Thus we only need to populate a texture with all of the colors in order. - // For other cases, we may have more colors than we can fit in the texture, - // or we may have very small stop values. For these gradients the lerped - // values are computed here and then populated in a texture. - uint32_t texture_size; - auto color_stop_channels = CreateGradientBuffer(colors, stops, &texture_size); + auto gradient_data = CreateGradientBuffer(colors, stops); + if (gradient_data.texture_size == 0) { + FML_DLOG(ERROR) << "Invalid gradient data."; + return nullptr; + } + impeller::TextureDescriptor texture_descriptor; texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible; texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt; - texture_descriptor.size = {texture_size, 1}; + texture_descriptor.size = {gradient_data.texture_size, 1}; auto texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); if (!texture) { @@ -38,7 +36,7 @@ std::shared_ptr CreateGradientTexture( return nullptr; } - auto mapping = std::make_shared(color_stop_channels); + auto mapping = std::make_shared(gradient_data.color_bytes); if (!texture->SetContents(mapping)) { FML_DLOG(ERROR) << "Could not copy contents into Impeller texture."; return nullptr; diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 18fdf1fd601b6..94de5fc8dd4f0 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -78,6 +78,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 4a82933ff1886..4ea83c93baecc 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -77,6 +77,7 @@ bool RadialGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index e24c6c2edaad1..57f022e15bb76 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -63,6 +63,7 @@ bool SolidColorContents::Render(const ContentContext& renderer, cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), cover_ ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : path_, diff --git a/impeller/entity/contents/solid_fill_utils.h b/impeller/entity/contents/solid_fill_utils.h index 2a8382fe5321c..6b5fb42739845 100644 --- a/impeller/entity/contents/solid_fill_utils.h +++ b/impeller/entity/contents/solid_fill_utils.h @@ -10,10 +10,12 @@ namespace impeller { template -VertexBuffer CreateSolidFillVertices(const Path& path, HostBuffer& buffer) { +VertexBuffer CreateSolidFillVertices(std::shared_ptr tessellator, + const Path& path, + HostBuffer& buffer) { VertexBufferBuilder vtx_builder; - auto tesselation_result = Tessellator{}.Tessellate( + auto tesselation_result = tessellator->Tessellate( path.GetFillType(), path.CreatePolyline(), [&vtx_builder](auto point) { vtx_builder.AppendVertex({point}); }); if (tesselation_result != Tessellator::Result::kSuccess) { diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index dfeff8e9260d3..fc6bf4aac4880 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -84,6 +84,7 @@ bool SweepGradientContents::Render(const ContentContext& renderer, OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index ad31dcde5040f..97b8aab0b3e68 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -99,35 +99,57 @@ static bool CommonRender(const ContentContext& renderer, // sample from the glyph atlas. const std::vector unit_vertex_points = { - {0, 0}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 1}, - }; + {0, 0}, {1, 0}, {0, 1}, {1, 1}}; + const std::vector indices = {0, 1, 2, 1, 2, 3}; VertexBufferBuilder vertex_builder; + + size_t count = 0; + for (const auto& run : frame.GetRuns()) { + count += run.GetGlyphPositions().size(); + } + + vertex_builder.Reserve(count * 4); + vertex_builder.ReserveIndices(count * 6); + + uint32_t offset = 0u; + for (auto i = 0u; i < count; i++) { + for (const auto& index : indices) { + vertex_builder.AppendIndex(index + offset); + } + offset += 4; + } + for (const auto& run : frame.GetRuns()) { auto font = run.GetFont(); - auto glyph_size = ISize::Ceil(font.GetMetrics().GetBoundingBox().size); + auto glyph_size_ = ISize::Ceil(font.GetMetrics().GetBoundingBox().size); + auto glyph_size = Point{static_cast(glyph_size_.width), + static_cast(glyph_size_.height)}; + auto metrics_offset = + Point{font.GetMetrics().min_extent.x, font.GetMetrics().ascent}; + for (const auto& glyph_position : run.GetGlyphPositions()) { FontGlyphPair font_glyph_pair{font, glyph_position.glyph}; + auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair); + if (!atlas_glyph_pos.has_value()) { + VALIDATION_LOG << "Could not find glyph position in the atlas."; + return false; + } + + auto atlas_position = + atlas_glyph_pos->origin + Point{1 / atlas_glyph_pos->size.width, + 1 / atlas_glyph_pos->size.height}; + auto atlas_glyph_size = + Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height}; + auto offset_glyph_position = glyph_position.position + metrics_offset; for (const auto& point : unit_vertex_points) { typename VS::PerVertexData vtx; vtx.unit_vertex = point; - - auto atlas_glyph_pos = atlas->FindFontGlyphPosition(font_glyph_pair); - if (!atlas_glyph_pos.has_value()) { - VALIDATION_LOG << "Could not find glyph position in the atlas."; - return false; - } - vtx.glyph_position = - glyph_position.position + - Point{font.GetMetrics().min_extent.x, font.GetMetrics().ascent}; - vtx.glyph_size = Point{static_cast(glyph_size.width), - static_cast(glyph_size.height)}; - vtx.atlas_position = - atlas_glyph_pos->origin + Point{1 / atlas_glyph_pos->size.width, - 1 / atlas_glyph_pos->size.height}; - vtx.atlas_glyph_size = - Point{atlas_glyph_pos->size.width, atlas_glyph_pos->size.height}; + vtx.glyph_position = offset_glyph_position; + vtx.glyph_size = glyph_size; + vtx.atlas_position = atlas_position; + vtx.atlas_glyph_size = atlas_glyph_size; if constexpr (std::is_same_v) { vtx.color_glyph = glyph_position.glyph.type == Glyph::Type::kBitmap ? 1.0 : 0.0; @@ -178,7 +200,7 @@ bool TextContents::Render(const ContentContext& renderer, } // This TextContents may be for a frame that doesn't have color, but the - // lazy atlas for this scene alraedy does have color. + // lazy atlas for this scene already does have color. // Benchmarks currently show that creating two atlases per pass regresses // render time. This should get re-evaluated if we start caching atlases // between frames or get significantly faster at creating atlases, because diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 282e8c0a54fd5..119a921bbe5cc 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -116,7 +116,7 @@ bool TextureContents::Render(const ContentContext& renderer, VertexBufferBuilder vertex_builder; { - const auto tess_result = Tessellator{}.Tessellate( + const auto tess_result = renderer.GetTessellator()->Tessellate( path_.GetFillType(), path_.CreatePolyline(), [this, &vertex_builder, &coverage_rect, &texture_size](Point vtx) { VS::PerVertexData data; diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index 52c60a5cd570f..ab4286d61b6b8 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -68,6 +68,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer, renderer.GetTiledTexturePipeline(OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(CreateSolidFillVertices( + renderer.GetTessellator(), GetCover() ? PathBuilder{}.AddRect(Size(pass.GetRenderTargetSize())).TakePath() : GetPath(), diff --git a/impeller/entity/shaders/linear_to_srgb_filter.frag b/impeller/entity/shaders/linear_to_srgb_filter.frag index 562bb5e119846..4d32b147dfe35 100644 --- a/impeller/entity/shaders/linear_to_srgb_filter.frag +++ b/impeller/entity/shaders/linear_to_srgb_filter.frag @@ -22,13 +22,14 @@ void main() { vec4 input_color = IPSample(input_texture, v_position, frag_info.texture_sampler_y_coord_scale); - for (int i = 0; i < 4; i++) { - if (input_color[i] <= 0.0031308) { - input_color[i] = input_color[i] * 12.92; + vec4 color = IPUnpremultiply(input_color); + for (int i = 0; i < 3; i++) { + if (color[i] <= 0.0031308) { + color[i] = (color[i]) * 12.92; } else { - input_color[i] = 1.055 * pow(input_color[i], (1.0 / 2.4)) - 0.055; + color[i] = 1.055 * pow(color[i], (1.0 / 2.4)) - 0.055; } } - frag_color = input_color; + frag_color = IPPremultiply(color); } diff --git a/impeller/entity/shaders/srgb_to_linear_filter.frag b/impeller/entity/shaders/srgb_to_linear_filter.frag index e18bd18f3b278..a8a82436ac5be 100644 --- a/impeller/entity/shaders/srgb_to_linear_filter.frag +++ b/impeller/entity/shaders/srgb_to_linear_filter.frag @@ -21,13 +21,14 @@ void main() { vec4 input_color = IPSample(input_texture, v_position, frag_info.texture_sampler_y_coord_scale); - for (int i = 0; i < 4; i++) { - if (input_color[i] <= 0.04045) { - input_color[i] = input_color[i] / 12.92; + vec4 color = IPUnpremultiply(input_color); + for (int i = 0; i < 3; i++) { + if (color[i] <= 0.04045) { + color[i] = color[i] / 12.92; } else { - input_color[i] = pow((input_color[i] + 0.055) / 1.055, 2.4); + color[i] = pow((color[i] + 0.055) / 1.055, 2.4); } } - frag_color = input_color; + frag_color = IPPremultiply(color); } diff --git a/impeller/fixtures/sample.comp b/impeller/fixtures/sample.comp index f7ffc47179c6f..39b505e016560 100644 --- a/impeller/fixtures/sample.comp +++ b/impeller/fixtures/sample.comp @@ -13,8 +13,18 @@ layout(binding = 2) readonly buffer Input1 { vec4 elements[]; } input_data1; +uniform Info { + uint count; +} info; + void main() { uint ident = gl_GlobalInvocationID.x; + // TODO(dnfield): https://github.com/flutter/flutter/issues/112683 + // We should be able to use length here instead of an extra arrgument. + if (ident >= info.count) { + return; + } + output_data.elements[ident] = input_data0.elements[ident] * input_data1.elements[ident]; } diff --git a/impeller/geometry/BUILD.gn b/impeller/geometry/BUILD.gn index 03865753d28f7..f34e00ad1558a 100644 --- a/impeller/geometry/BUILD.gn +++ b/impeller/geometry/BUILD.gn @@ -42,6 +42,8 @@ impeller_component("geometry") { "vertices.cc", "vertices.h", ] + + deps = [ "//flutter/fml" ] } impeller_component("geometry_unittests") { diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index f2fed24cf4d12..a199c689d77fd 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1650,12 +1650,11 @@ TEST(GeometryTest, Gradient) { // values. std::vector colors = {Color::Red(), Color::Blue()}; std::vector stops = {0.0, 1.0}; - uint32_t texture_size; - auto gradient = CreateGradientBuffer(colors, stops, &texture_size); + auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLOR_BUFFER_NEAR(gradient, colors); - ASSERT_EQ(texture_size, 2u); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); + ASSERT_EQ(gradient.texture_size, 2u); } { @@ -1663,10 +1662,9 @@ TEST(GeometryTest, Gradient) { std::vector colors = {Color::Red(), Color::Yellow(), Color::Black(), Color::Blue()}; std::vector stops = {0.0, 0.25, 0.25, 1.0}; - uint32_t texture_size; - auto gradient = CreateGradientBuffer(colors, stops, &texture_size); - ASSERT_EQ(texture_size, 5u); + auto gradient = CreateGradientBuffer(colors, stops); + ASSERT_EQ(gradient.texture_size, 5u); } { @@ -1675,21 +1673,19 @@ TEST(GeometryTest, Gradient) { std::vector colors = {Color::Red(), Color::Blue(), Color::Green(), Color::White()}; std::vector stops = {0.0, 0.33, 0.66, 1.0}; - uint32_t texture_size; - auto gradient = CreateGradientBuffer(colors, stops, &texture_size); + auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLOR_BUFFER_NEAR(gradient, colors); - ASSERT_EQ(texture_size, 4u); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); + ASSERT_EQ(gradient.texture_size, 4u); } { // Gradient with color stops will lerp and scale buffer. std::vector colors = {Color::Red(), Color::Blue(), Color::Green()}; std::vector stops = {0.0, 0.25, 1.0}; - uint32_t texture_size; - auto gradient = CreateGradientBuffer(colors, stops, &texture_size); + auto gradient = CreateGradientBuffer(colors, stops); std::vector lerped_colors = { Color::Red(), @@ -1698,8 +1694,8 @@ TEST(GeometryTest, Gradient) { Color::lerp(Color::Blue(), Color::Green(), 0.6666), Color::Green(), }; - ASSERT_COLOR_BUFFER_NEAR(gradient, lerped_colors); - ASSERT_EQ(texture_size, 5u); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors); + ASSERT_EQ(gradient.texture_size, 5u); } { @@ -1711,10 +1707,9 @@ TEST(GeometryTest, Gradient) { stops.push_back(i / 1025.0); } - uint32_t texture_size; - auto gradient = CreateGradientBuffer(colors, stops, &texture_size); + auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_EQ(texture_size, 1024u); + ASSERT_EQ(gradient.texture_size, 1024u); } } diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 8be11718b631e..fc0f52b957ed3 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -4,6 +4,7 @@ #include +#include "flutter/fml/logging.h" #include "impeller/geometry/gradient.h" namespace impeller { @@ -16,14 +17,13 @@ static void AppendColor(const Color& color, std::vector* colors) { colors->push_back(converted[3]); } -std::vector CreateGradientBuffer(const std::vector& colors, - const std::vector& stops, - uint32_t* out_texture_size) { +GradientData CreateGradientBuffer(const std::vector& colors, + const std::vector& stops) { + FML_DCHECK(stops.size() == colors.size()); + uint32_t texture_size; - // TODO(jonahwilliams): we should add a display list flag to check if the - // stops were provided or not, then we can skip this step. if (stops.size() == 2) { - texture_size = 2; + texture_size = colors.size(); } else { auto minimum_delta = 1.0; for (size_t i = 1; i < stops.size(); i++) { @@ -43,7 +43,6 @@ std::vector CreateGradientBuffer(const std::vector& colors, texture_size = std::min((uint32_t)std::round(1.0 / minimum_delta) + 1, 1024u); } - *out_texture_size = texture_size; std::vector color_stop_channels; color_stop_channels.reserve(texture_size * 4); @@ -60,7 +59,7 @@ std::vector CreateGradientBuffer(const std::vector& colors, AppendColor(previous_color, &color_stop_channels); for (auto i = 1u; i < texture_size - 1; i++) { - auto scaled_i = i / (texture_size * 1.0); + auto scaled_i = i / (texture_size - 1.0); Color next_color = colors[previous_color_index + 1]; auto next_stop = stops[previous_color_index + 1]; // We're almost exactly equal to the next stop. @@ -93,7 +92,10 @@ std::vector CreateGradientBuffer(const std::vector& colors, // The last index is always equal to the last color, exactly. AppendColor(colors.back(), &color_stop_channels); } - return color_stop_channels; + return GradientData{ + .color_bytes = std::move(color_stop_channels), + .texture_size = texture_size, + }; } } // namespace impeller diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index 2e99e89ba0f97..d9f943de77177 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -13,16 +13,21 @@ namespace impeller { +// If texture_size is 0 then the gradient is invalid. +struct GradientData { + std::vector color_bytes; + uint32_t texture_size; +}; + /** * @brief Populate a vector with the interpolated colors for the linear gradient * described colors and stops. * * @param colors * @param stops - * @return std::vector + * @return GradientData */ -std::vector CreateGradientBuffer(const std::vector& colors, - const std::vector& stops, - uint32_t* out_texture_size); +GradientData CreateGradientBuffer(const std::vector& colors, + const std::vector& stops); } // namespace impeller diff --git a/impeller/geometry/vector.h b/impeller/geometry/vector.h index 10066340a5be8..96821e3f1984c 100644 --- a/impeller/geometry/vector.h +++ b/impeller/geometry/vector.h @@ -232,6 +232,10 @@ struct Vector4 { return Vector4(x * f, y * f, z * f, w * f); } + constexpr Vector4 operator*(const Vector4& v) const { + return Vector4(x * v.x, y * v.y, z * v.z, w * v.w); + } + constexpr Vector4 Lerp(const Vector4& v, Scalar t) const { return *this + (v - *this) * t; } diff --git a/impeller/renderer/allocator.cc b/impeller/renderer/allocator.cc index c8ad3ec459fb5..297cb48f2a4d9 100644 --- a/impeller/renderer/allocator.cc +++ b/impeller/renderer/allocator.cc @@ -58,4 +58,8 @@ std::shared_ptr Allocator::CreateTexture( return OnCreateTexture(desc); } +uint16_t Allocator::MinimumBytesPerRow(PixelFormat format) const { + return BytesPerPixelForPixelFormat(format); +} + } // namespace impeller diff --git a/impeller/renderer/allocator.h b/impeller/renderer/allocator.h index 225fec0ba6dff..6dfec0652f207 100644 --- a/impeller/renderer/allocator.h +++ b/impeller/renderer/allocator.h @@ -31,6 +31,12 @@ class Allocator { std::shared_ptr CreateTexture(const TextureDescriptor& desc); + //------------------------------------------------------------------------------ + /// @brief Minimum value for `row_bytes` on a Texture. The row + /// bytes parameter of that method must be aligned to this value. + /// + virtual uint16_t MinimumBytesPerRow(PixelFormat format) const; + std::shared_ptr CreateBufferWithCopy(const uint8_t* buffer, size_t length); diff --git a/impeller/renderer/backend/gles/device_buffer_gles.cc b/impeller/renderer/backend/gles/device_buffer_gles.cc index ffb9f2543adbb..54a7d1fb10202 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -30,6 +30,14 @@ DeviceBufferGLES::~DeviceBufferGLES() { } } +// |DeviceBuffer| +uint8_t* DeviceBufferGLES::OnGetContents() const { + if (!reactor_) { + return nullptr; + } + return backing_store_->GetBuffer(); +} + // |DeviceBuffer| bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source, Range source_range, diff --git a/impeller/renderer/backend/gles/device_buffer_gles.h b/impeller/renderer/backend/gles/device_buffer_gles.h index 3e002e586ca8f..fe572d7e3590a 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/impeller/renderer/backend/gles/device_buffer_gles.h @@ -41,6 +41,9 @@ class DeviceBufferGLES final mutable uint32_t generation_ = 0; mutable uint32_t upload_generation_ = 0; + // |DeviceBuffer| + uint8_t* OnGetContents() const override; + // |DeviceBuffer| bool OnCopyHostBuffer(const uint8_t* source, Range source_range, diff --git a/impeller/renderer/backend/metal/allocator_mtl.h b/impeller/renderer/backend/metal/allocator_mtl.h index 8d6e4565b4145..c1cca04c81227 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.h +++ b/impeller/renderer/backend/metal/allocator_mtl.h @@ -41,6 +41,9 @@ class AllocatorMTL final : public Allocator { std::shared_ptr OnCreateTexture( const TextureDescriptor& desc) override; + // |Allocator| + uint16_t MinimumBytesPerRow(PixelFormat format) const override; + // |Allocator| ISize GetMaxTextureSizeSupported() const override; diff --git a/impeller/renderer/backend/metal/allocator_mtl.mm b/impeller/renderer/backend/metal/allocator_mtl.mm index da64bff2eb270..9722a80437c55 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.mm +++ b/impeller/renderer/backend/metal/allocator_mtl.mm @@ -201,6 +201,11 @@ static MTLStorageMode ToMTLStorageMode(StorageMode mode, return std::make_shared(desc, texture); } +uint16_t AllocatorMTL::MinimumBytesPerRow(PixelFormat format) const { + return static_cast([device_ + minimumLinearTextureAlignmentForPixelFormat:ToMTLPixelFormat(format)]); +} + ISize AllocatorMTL::GetMaxTextureSizeSupported() const { return max_texture_supported_; } diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.h b/impeller/renderer/backend/metal/device_buffer_mtl.h index 3835c84f392ff..ab4914d37fc9a 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.h +++ b/impeller/renderer/backend/metal/device_buffer_mtl.h @@ -33,6 +33,14 @@ class DeviceBufferMTL final id buffer, MTLStorageMode storage_mode); + // |DeviceBuffer| + uint8_t* OnGetContents() const override; + + // |DeviceBuffer| + std::shared_ptr AsTexture(Allocator& allocator, + const TextureDescriptor& descriptor, + uint16_t row_bytes) const override; + // |DeviceBuffer| bool OnCopyHostBuffer(const uint8_t* source, Range source_range, diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.mm b/impeller/renderer/backend/metal/device_buffer_mtl.mm index 123ef1263213c..81aa2387c6c9a 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/device_buffer_mtl.mm @@ -22,6 +22,34 @@ return buffer_; } +uint8_t* DeviceBufferMTL::OnGetContents() const { + if (storage_mode_ != MTLStorageModeShared) { + return nullptr; + } + + return reinterpret_cast(buffer_.contents); +} + +std::shared_ptr DeviceBufferMTL::AsTexture( + Allocator& allocator, + const TextureDescriptor& descriptor, + uint16_t row_bytes) const { + auto mtl_texture_desc = ToMTLTextureDescriptor(descriptor); + + if (!mtl_texture_desc) { + VALIDATION_LOG << "Texture descriptor was invalid."; + return nullptr; + } + + auto texture = [buffer_ newTextureWithDescriptor:mtl_texture_desc + offset:0 + bytesPerRow:row_bytes]; + if (!texture) { + return nullptr; + } + return std::make_shared(descriptor, texture); +} + [[nodiscard]] bool DeviceBufferMTL::OnCopyHostBuffer(const uint8_t* source, Range source_range, size_t offset) { diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.cc b/impeller/renderer/backend/vulkan/device_buffer_vk.cc index 20c1ca9118759..02e7eea14ca9d 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.cc @@ -45,6 +45,10 @@ DeviceBufferVK::DeviceBufferVK( DeviceBufferVK::~DeviceBufferVK() = default; +uint8_t* DeviceBufferVK::OnGetContents() const { + return reinterpret_cast(device_allocation_->GetMapping()); +} + bool DeviceBufferVK::OnCopyHostBuffer(const uint8_t* source, Range source_range, size_t offset) { diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index a862d8977ea98..59aa773b3a15b 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h @@ -53,6 +53,9 @@ class DeviceBufferVK final : public DeviceBuffer, ContextVK& context_; std::unique_ptr device_allocation_; + // |DeviceBuffer| + uint8_t* OnGetContents() const override; + // |DeviceBuffer| bool OnCopyHostBuffer(const uint8_t* source, Range source_range, diff --git a/impeller/renderer/buffer_view.h b/impeller/renderer/buffer_view.h index eb70e1312a6bf..21a04655d645a 100644 --- a/impeller/renderer/buffer_view.h +++ b/impeller/renderer/buffer_view.h @@ -12,6 +12,7 @@ namespace impeller { struct BufferView { std::shared_ptr buffer; + uint8_t* contents; Range range; constexpr operator bool() const { return static_cast(buffer); } diff --git a/impeller/renderer/compute_unittests.cc b/impeller/renderer/compute_unittests.cc index c392bd9cead4f..2656da901a54d 100644 --- a/impeller/renderer/compute_unittests.cc +++ b/impeller/renderer/compute_unittests.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/time/time_point.h" #include "flutter/testing/testing.h" #include "impeller/base/strings.h" @@ -46,20 +47,51 @@ TEST_P(ComputeTest, CanCreateComputePass) { cmd.label = "Compute"; cmd.pipeline = compute_pipeline; + CS::Info info{.count = 5}; std::vector input_0; std::vector input_1; - input_0.push_back(CS::Input0{Vector4(2.0, 3.0, 4.0, 5.0)}); - input_1.push_back(CS::Input1{Vector4(6.0, 7.0, 8.0, 9.0)}); + for (uint i = 0; i < 5; i++) { + input_0.push_back(CS::Input0{Vector4(2.0 + i, 3.0 + i, 4.0 + i, 5.0 * i)}); + input_1.push_back(CS::Input1{Vector4(6.0, 7.0, 8.0, 9.0)}); + } + + DeviceBufferDescriptor buffer_desc; + buffer_desc.storage_mode = StorageMode::kHostVisible; + buffer_desc.size = sizeof(CS::Output) * 5; - std::vector output(5); + auto output_buffer = + context->GetResourceAllocator()->CreateBuffer(buffer_desc); + output_buffer->SetLabel("Output Buffer"); + + CS::BindInfo(cmd, pass->GetTransientsBuffer().EmplaceUniform(info)); CS::BindInput0(cmd, pass->GetTransientsBuffer().EmplaceStorageBuffer(input_0)); CS::BindInput1(cmd, pass->GetTransientsBuffer().EmplaceStorageBuffer(input_1)); - CS::BindOutput(cmd, pass->GetTransientsBuffer().EmplaceStorageBuffer(output)); + CS::BindOutput(cmd, output_buffer->AsBufferView()); ASSERT_TRUE(pass->AddCommand(std::move(cmd))); ASSERT_TRUE(pass->EncodeCommands()); + + fml::AutoResetWaitableEvent latch; + ASSERT_TRUE( + cmd_buffer->SubmitCommands([&latch, output_buffer, &input_0, + &input_1](CommandBuffer::Status status) { + EXPECT_EQ(status, CommandBuffer::Status::kCompleted); + + auto view = output_buffer->AsBufferView(); + EXPECT_EQ(view.range.length, 80lu); + + for (size_t i = 0; i < input_0.size() - 1; i++) { + Vector4 output = reinterpret_cast(view.contents + + i * sizeof(CS::Output)) + ->elements; + EXPECT_EQ(output, input_0[i].elements * input_1[i].elements); + } + latch.Signal(); + })); + + latch.Wait(); } } // namespace testing diff --git a/impeller/renderer/device_buffer.cc b/impeller/renderer/device_buffer.cc index ff07f6eda9c34..6bb706d8bb98b 100644 --- a/impeller/renderer/device_buffer.cc +++ b/impeller/renderer/device_buffer.cc @@ -19,10 +19,26 @@ std::shared_ptr DeviceBuffer::GetDeviceBuffer( BufferView DeviceBuffer::AsBufferView() const { BufferView view; view.buffer = shared_from_this(); + view.contents = OnGetContents(); view.range = {0u, desc_.size}; return view; } +std::shared_ptr DeviceBuffer::AsTexture( + Allocator& allocator, + const TextureDescriptor& descriptor, + uint16_t row_bytes) const { + auto texture = allocator.CreateTexture(descriptor); + if (!texture) { + return nullptr; + } + if (!texture->SetContents(std::make_shared( + OnGetContents(), desc_.size))) { + return nullptr; + } + return texture; +} + [[nodiscard]] bool DeviceBuffer::CopyHostBuffer(const uint8_t* source, Range source_range, size_t offset) { diff --git a/impeller/renderer/device_buffer.h b/impeller/renderer/device_buffer.h index 4e9f7a05af08b..e86fa2a7e7f93 100644 --- a/impeller/renderer/device_buffer.h +++ b/impeller/renderer/device_buffer.h @@ -32,6 +32,11 @@ class DeviceBuffer : public Buffer, BufferView AsBufferView() const; + virtual std::shared_ptr AsTexture( + Allocator& allocator, + const TextureDescriptor& descriptor, + uint16_t row_bytes) const; + // |Buffer| std::shared_ptr GetDeviceBuffer( Allocator& allocator) const; @@ -41,6 +46,8 @@ class DeviceBuffer : public Buffer, explicit DeviceBuffer(DeviceBufferDescriptor desc); + virtual uint8_t* OnGetContents() const = 0; + virtual bool OnCopyHostBuffer(const uint8_t* source, Range source_range, size_t offset) = 0; diff --git a/impeller/renderer/host_buffer.cc b/impeller/renderer/host_buffer.cc index 16f9b62fbda80..84fbebc740369 100644 --- a/impeller/renderer/host_buffer.cc +++ b/impeller/renderer/host_buffer.cc @@ -53,7 +53,7 @@ BufferView HostBuffer::Emplace(const void* buffer, size_t length) { if (buffer) { ::memmove(GetBuffer() + old_length, buffer, length); } - return BufferView{shared_from_this(), Range{old_length, length}}; + return BufferView{shared_from_this(), GetBuffer(), Range{old_length, length}}; } std::shared_ptr HostBuffer::GetDeviceBuffer( diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index 41bab917289e7..dbd4712d89e9d 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -841,5 +841,64 @@ TEST_P(RendererTest, InactiveUniforms) { OpenPlaygroundHere(callback); } +TEST_P(RendererTest, CanCreateCPUBackedTexture) { + if (GetParam() != PlaygroundBackend::kMetal) { + GTEST_SKIP_("CPU backed textures only supported on Metal right now."); + } + + auto context = GetContext(); + auto allocator = context->GetResourceAllocator(); + size_t dimension = 2; + + do { + ISize size(dimension, dimension); + TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt; + texture_descriptor.size = size; + auto row_bytes = + std::max(static_cast(size.width * 4), + allocator->MinimumBytesPerRow(texture_descriptor.format)); + auto buffer_size = size.height * row_bytes; + + DeviceBufferDescriptor buffer_descriptor; + buffer_descriptor.storage_mode = StorageMode::kHostVisible; + buffer_descriptor.size = buffer_size; + + auto buffer = allocator->CreateBuffer(buffer_descriptor); + + ASSERT_TRUE(buffer); + + auto texture = buffer->AsTexture(*allocator, texture_descriptor, row_bytes); + + ASSERT_TRUE(texture); + ASSERT_TRUE(texture->IsValid()); + + dimension *= 2; + } while (dimension <= 8192); +} + +TEST_P(RendererTest, VertexBufferBuilder) { + // Does not create index buffer if one is provided. + using VS = BoxFadeVertexShader; + VertexBufferBuilder vertex_builder; + vertex_builder.SetLabel("Box"); + vertex_builder.AddVertices({ + {{100, 100, 0.0}, {0.0, 0.0}}, // 1 + {{800, 100, 0.0}, {1.0, 0.0}}, // 2 + {{800, 800, 0.0}, {1.0, 1.0}}, // 3 + {{100, 800, 0.0}, {0.0, 1.0}}, // 4 + }); + vertex_builder.AppendIndex(0); + vertex_builder.AppendIndex(1); + vertex_builder.AppendIndex(2); + vertex_builder.AppendIndex(1); + vertex_builder.AppendIndex(2); + vertex_builder.AppendIndex(3); + + ASSERT_EQ(vertex_builder.GetIndexCount(), 6u); + ASSERT_EQ(vertex_builder.GetVertexCount(), 4u); +} + } // namespace testing } // namespace impeller diff --git a/impeller/renderer/vertex_buffer_builder.h b/impeller/renderer/vertex_buffer_builder.h index 7222537b91f31..b5886b00cfaf0 100644 --- a/impeller/renderer/vertex_buffer_builder.h +++ b/impeller/renderer/vertex_buffer_builder.h @@ -43,10 +43,16 @@ class VertexBufferBuilder { void Reserve(size_t count) { return vertices_.reserve(count); } + void ReserveIndices(size_t count) { return indices_.reserve(count); } + bool HasVertices() const { return !vertices_.empty(); } size_t GetVertexCount() const { return vertices_.size(); } + size_t GetIndexCount() const { + return indices_.size() > 0 ? indices_.size() : vertices_.size(); + } + VertexBufferBuilder& AppendVertex(VertexType_ vertex) { vertices_.emplace_back(std::move(vertex)); return *this; @@ -61,6 +67,11 @@ class VertexBufferBuilder { return *this; } + VertexBufferBuilder& AppendIndex(IndexType_ index) { + indices_.emplace_back(index); + return *this; + } + VertexBuffer CreateVertexBuffer(HostBuffer& host_buffer) const { VertexBuffer buffer; buffer.vertex_buffer = CreateVertexBufferView(host_buffer); @@ -81,9 +92,8 @@ class VertexBufferBuilder { }; private: - // This is a placeholder till vertex de-duplication can be implemented. The - // current implementation is a very dumb placeholder. std::vector vertices_; + std::vector indices_; std::string label_; BufferView CreateVertexBufferView(HostBuffer& buffer) const { @@ -106,6 +116,10 @@ class VertexBufferBuilder { } std::vector CreateIndexBuffer() const { + if (indices_.size() > 0) { + return indices_; + } + // So dumb! We don't actually need an index buffer right now. But we will // once de-duplication is done. So assume this is always done. std::vector index_buffer; @@ -135,8 +149,6 @@ class VertexBufferBuilder { } return buffer->AsBufferView(); } - - size_t GetIndexCount() const { return vertices_.size(); } }; } // namespace impeller diff --git a/impeller/tessellator/c/tessellator.cc b/impeller/tessellator/c/tessellator.cc index bb11fb145c84d..7a53d9ceded5d 100644 --- a/impeller/tessellator/c/tessellator.cc +++ b/impeller/tessellator/c/tessellator.cc @@ -45,7 +45,6 @@ struct Vertices* Tessellate(PathBuilder* builder, auto path = builder->CopyPath(static_cast(fill_type)); auto smoothing = SmoothingApproximation(scale, angle_tolerance, cusp_limit); auto polyline = path.CreatePolyline(smoothing); - std::vector points; if (Tessellator{}.Tessellate(path.GetFillType(), polyline, [&points](Point vertex) { diff --git a/impeller/tessellator/tessellator.cc b/impeller/tessellator/tessellator.cc index 0b4176f930985..603532d095c0b 100644 --- a/impeller/tessellator/tessellator.cc +++ b/impeller/tessellator/tessellator.cc @@ -8,7 +8,31 @@ namespace impeller { -Tessellator::Tessellator() = default; +static void* HeapAlloc(void* userData, unsigned int size) { + return malloc(size); +} + +static void* HeapRealloc(void* userData, void* ptr, unsigned int size) { + return realloc(ptr, size); +} + +static void HeapFree(void* userData, void* ptr) { + free(ptr); +} + +// Note: these units are "number of entities" for bucket size and not in KB. +static TESSalloc alloc = { + HeapAlloc, HeapRealloc, HeapFree, 0, /* =userData */ + 16, /* =meshEdgeBucketSize */ + 16, /* =meshVertexBucketSize */ + 16, /* =meshFaceBucketSize */ + 16, /* =dictNodeBucketSize */ + 16, /* =regionBucketSize */ + 0 /* =extraVertices */ +}; + +Tessellator::Tessellator() + : c_tessellator_(::tessNewTess(&alloc), &DestroyTessellator) {} Tessellator::~Tessellator() = default; @@ -28,12 +52,6 @@ static int ToTessWindingRule(FillType fill_type) { return TESS_WINDING_ODD; } -static void DestroyTessellator(TESStesselator* tessellator) { - if (tessellator != nullptr) { - ::tessDeleteTess(tessellator); - } -} - Tessellator::Result Tessellator::Tessellate( FillType fill_type, const Path::Polyline& polyline, @@ -46,13 +64,7 @@ Tessellator::Result Tessellator::Tessellate( return Result::kInputError; } - using CTessellator = - std::unique_ptr; - - CTessellator tessellator( - ::tessNewTess(nullptr /* the default ::malloc based allocator */), - DestroyTessellator); - + auto tessellator = c_tessellator_.get(); if (!tessellator) { return Result::kTessellationError; } @@ -70,8 +82,8 @@ Tessellator::Result Tessellator::Tessellate( std::tie(start_point_index, end_point_index) = polyline.GetContourPointBounds(contour_i); - ::tessAddContour(tessellator.get(), // the C tessellator - kVertexSize, // + ::tessAddContour(tessellator, // the C tessellator + kVertexSize, // polyline.points.data() + start_point_index, // sizeof(Point), // end_point_index - start_point_index // @@ -81,7 +93,7 @@ Tessellator::Result Tessellator::Tessellate( //---------------------------------------------------------------------------- /// Let's tessellate. /// - auto result = ::tessTesselate(tessellator.get(), // tessellator + auto result = ::tessTesselate(tessellator, // tessellator ToTessWindingRule(fill_type), // winding TESS_POLYGONS, // element type kPolygonSize, // polygon size @@ -97,14 +109,14 @@ Tessellator::Result Tessellator::Tessellate( std::vector points; std::vector indices; - int vertexItemCount = tessGetVertexCount(tessellator.get()) * kVertexSize; - auto vertices = tessGetVertices(tessellator.get()); + int vertexItemCount = tessGetVertexCount(tessellator) * kVertexSize; + auto vertices = tessGetVertices(tessellator); for (int i = 0; i < vertexItemCount; i += 2) { points.emplace_back(vertices[i], vertices[i + 1]); } - int elementItemCount = tessGetElementCount(tessellator.get()) * kPolygonSize; - auto elements = tessGetElements(tessellator.get()); + int elementItemCount = tessGetElementCount(tessellator) * kPolygonSize; + auto elements = tessGetElements(tessellator); for (int i = 0; i < elementItemCount; i++) { indices.emplace_back(elements[i]); } @@ -113,8 +125,13 @@ Tessellator::Result Tessellator::Tessellate( auto vtx = points[index]; callback(vtx); } - return Result::kSuccess; } +void DestroyTessellator(TESStesselator* tessellator) { + if (tessellator != nullptr) { + ::tessDeleteTess(tessellator); + } +} + } // namespace impeller diff --git a/impeller/tessellator/tessellator.h b/impeller/tessellator/tessellator.h index 595fb68acb8b3..7a2fded0e8ebc 100644 --- a/impeller/tessellator/tessellator.h +++ b/impeller/tessellator/tessellator.h @@ -11,8 +11,15 @@ #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" +struct TESStesselator; + namespace impeller { +void DestroyTessellator(TESStesselator* tessellator); + +using CTessellator = + std::unique_ptr; + enum class WindingOrder { kClockwise, kCounterClockwise, @@ -52,6 +59,8 @@ class Tessellator { const VertexCallback& callback) const; private: + CTessellator c_tessellator_; + FML_DISALLOW_COPY_AND_ASSIGN(Tessellator); }; diff --git a/impeller/tessellator/tessellator_unittests.cc b/impeller/tessellator/tessellator_unittests.cc index 6f0b6bab804a5..f9184b6805a42 100644 --- a/impeller/tessellator/tessellator_unittests.cc +++ b/impeller/tessellator/tessellator_unittests.cc @@ -44,6 +44,22 @@ TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) { ASSERT_EQ(polyline.points.size(), 2u); ASSERT_EQ(result, Tessellator::Result::kSuccess); } + + // Many points. + { + Tessellator t; + PathBuilder builder; + for (int i = 0; i < 1000; i++) { + auto coord = i * 1.0f; + builder.AddLine({coord, coord}, {coord + 1, coord + 1}); + } + auto polyline = builder.TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + + ASSERT_EQ(polyline.points.size(), 2000u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); + } } } // namespace testing diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 96ef3f6851839..9002452427e55 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -4,12 +4,14 @@ #include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include #include #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/base/allocation.h" #include "impeller/renderer/allocator.h" +#include "impeller/renderer/device_buffer.h" #include "impeller/typographer/backends/skia/typeface_skia.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -238,32 +240,59 @@ static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, #undef nearestpt } -static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, - const ISize& atlas_size) { +static std::shared_ptr CreateAtlasTexture( + const std::shared_ptr& allocator, + const GlyphAtlas& atlas, + const ISize& atlas_size) { TRACE_EVENT0("impeller", __FUNCTION__); auto bitmap = std::make_shared(); SkImageInfo image_info; + PixelFormat format; switch (atlas.GetType()) { case GlyphAtlas::Type::kSignedDistanceField: case GlyphAtlas::Type::kAlphaBitmap: + format = PixelFormat::kA8UNormInt; image_info = SkImageInfo::MakeA8(atlas_size.width, atlas_size.height); break; case GlyphAtlas::Type::kColorBitmap: + format = PixelFormat::kR8G8B8A8UNormInt; image_info = SkImageInfo::MakeN32Premul(atlas_size.width, atlas_size.height); break; } - if (!bitmap->tryAllocPixels(image_info)) { + auto row_bytes = + std::max(static_cast(image_info.minRowBytes()), + static_cast(allocator->MinimumBytesPerRow(format))); + + DeviceBufferDescriptor buffer_descriptor; + buffer_descriptor.storage_mode = StorageMode::kHostVisible; + buffer_descriptor.size = image_info.computeByteSize(row_bytes); + + auto buffer = allocator->CreateBuffer(buffer_descriptor); + if (!buffer) { + return nullptr; + } + + auto pixels = reinterpret_cast(buffer->AsBufferView().contents); + if (!pixels) { + FML_LOG(ERROR) << "No pixels"; + return nullptr; + } + + if (!bitmap->installPixels(image_info, pixels, row_bytes)) { + FML_LOG(ERROR) << "No install pixels"; return nullptr; } auto surface = SkSurface::MakeRasterDirect(bitmap->pixmap()); if (!surface) { + FML_LOG(ERROR) << "No surf"; return nullptr; } auto canvas = surface->getCanvas(); if (!canvas) { + FML_LOG(ERROR) << "No canv"; return nullptr; } @@ -294,48 +323,20 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return true; }); - return bitmap; -} - -static std::shared_ptr UploadGlyphTextureAtlas( - const std::shared_ptr& allocator, - std::shared_ptr bitmap, - const ISize& atlas_size, - PixelFormat format) { - TRACE_EVENT0("impeller", __FUNCTION__); - if (!allocator) { - return nullptr; + if (atlas.GetType() == GlyphAtlas::Type::kSignedDistanceField) { + ConvertBitmapToSignedDistanceField( + reinterpret_cast(bitmap->getPixels()), atlas_size.width, + atlas_size.height); } - FML_DCHECK(bitmap != nullptr); - const auto& pixmap = bitmap->pixmap(); - - TextureDescriptor texture_descriptor; - texture_descriptor.storage_mode = StorageMode::kHostVisible; - texture_descriptor.format = format; - texture_descriptor.size = atlas_size; - - if (pixmap.rowBytes() * pixmap.height() != - texture_descriptor.GetByteSizeOfBaseMipLevel()) { - return nullptr; + { + TRACE_EVENT0("impeller", "Texture Creation/Upload"); + TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = format; + texture_descriptor.size = atlas_size; + return buffer->AsTexture(*allocator, texture_descriptor, row_bytes); } - - auto texture = allocator->CreateTexture(texture_descriptor); - if (!texture || !texture->IsValid()) { - return nullptr; - } - texture->SetLabel("GlyphAtlas"); - - auto mapping = std::make_shared( - reinterpret_cast(bitmap->getAddr(0, 0)), // data - texture_descriptor.GetByteSizeOfBaseMipLevel(), // size - [bitmap](auto, auto) mutable { bitmap.reset(); } // proc - ); - - if (!texture->SetContents(mapping)) { - return nullptr; - } - return texture; } std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( @@ -386,37 +387,19 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 5: Draw font-glyph pairs in the correct spot in the atlas. + // Step 5: Create a texture and draw font-glyph pairs in the correct spot in + // the atlas. // --------------------------------------------------------------------------- - auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); - if (!bitmap) { - return nullptr; - } - // --------------------------------------------------------------------------- - // Step 6: Upload the atlas as a texture. - // --------------------------------------------------------------------------- - PixelFormat format; - switch (type) { - case GlyphAtlas::Type::kSignedDistanceField: - ConvertBitmapToSignedDistanceField( - reinterpret_cast(bitmap->getPixels()), atlas_size.width, - atlas_size.height); - case GlyphAtlas::Type::kAlphaBitmap: - format = PixelFormat::kA8UNormInt; - break; - case GlyphAtlas::Type::kColorBitmap: - format = PixelFormat::kR8G8B8A8UNormInt; - break; - } - auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(), - bitmap, atlas_size, format); + auto texture = CreateAtlasTexture(GetContext()->GetResourceAllocator(), + *glyph_atlas, atlas_size); + if (!texture) { return nullptr; } // --------------------------------------------------------------------------- - // Step 7: Record the texture in the glyph atlas. + // Step 6: Record the texture in the glyph atlas. // --------------------------------------------------------------------------- glyph_atlas->SetTexture(std::move(texture)); diff --git a/lib/snapshot/BUILD.gn b/lib/snapshot/BUILD.gn index bf08b11d865b5..22930d5c8bcdf 100644 --- a/lib/snapshot/BUILD.gn +++ b/lib/snapshot/BUILD.gn @@ -6,31 +6,51 @@ import("//build/compiled_action.gni") import("//build/fuchsia/sdk.gni") import("//flutter/common/config.gni") import("//flutter/lib/ui/dart_ui.gni") -import("//flutter/sky/tools/macos_snapshots.gni") +import("//flutter/sky/tools/macos.gni") import("//third_party/dart/utils/compile_platform.gni") +# Generates the Dart/Flutter core platform files and tools. +# +# This target generates the platform-specific snapshots and snapshot-related +# tooling for a given target CPU. +# +# Outputs: +# * Core platform compiled to kernel bytecode +# * Core platform compiled to target_cpu-specific binary snapshot +# * target_cpu-specific gen_snapshot +# * target_cpu-specific analyze_snapshot group("generate_snapshot_bins") { deps = [ ":generate_snapshot_bin", ":kernel_platform_files", ] - if (host_os == "mac" && (target_cpu == "arm" || target_cpu == "arm64")) { - deps += [ ":create_arm_gen_snapshot" ] - } + + # Build gen_snapshot for the currently specified target_cpu. + # + # For macOS target builds: needed for both target CPUs (arm64, x64). + # For iOS, Android target builds: all AOT target CPUs are arm/arm64. if (host_os == "mac" && target_os == "mac") { deps += [ ":create_macos_gen_snapshots" ] + } else if (host_os == "mac" && + (target_cpu == "arm" || target_cpu == "arm64")) { + deps += [ ":create_arm_gen_snapshot" ] } + + # Build analyze_snapshot for for 64-bit target CPUs. if (target_cpu == "x64" || target_cpu == "arm64") { deps += [ "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)" ] } } -# Uses gen_snapshot to compile a Dart core platform snapshot. +# Compiles a binary snapshot of the core Dart/Flutter platform. # # Inputs: # * platform_strong.dill # +# Tools: +# * gen_snapshot +# # Outputs: # * vm_snapshot_data.bin # * vm_snapshot_instructions.bin @@ -223,46 +243,56 @@ bin_to_linkable("platform_strong_dill_linkable") { executable = false } -# Creates a `gen_snapshot` binary suffixed with the target platform. +# Creates a `gen_snapshot` binary suffixed with the target CPU architecture. # # Builds gen_snapshot using the host toolchain then copies the resulting binary # to `gen_snapshot_armv7` or `gen_snapshot_arm64` depending on the target # platform. -if (host_os == "mac" && (target_cpu == "arm" || target_cpu == "arm64")) { - action("create_arm_gen_snapshot") { +# +# This target is used for builds targeting iOS/Android OS. +if (host_os == "mac" && target_os != "mac" && + (target_cpu == "arm" || target_cpu == "arm64")) { + strip_bitcode("create_arm_gen_snapshot") { + # The toolchain-specific output directory. For cross-compiles, this is a + # clang-x64 or clang-arm64 subdirectory of the top-level build directory. host_output_dir = get_label_info( "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", "root_out_dir") - clang_dir = rebase_path(host_output_dir, root_build_dir) - script = "//flutter/sky/tools/create_macos_gen_snapshots.py" - visibility = [ ":*" ] - deps = [ "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)" ] - args = [ - "--dst", - rebase_path(host_output_dir), - "--clang-dir", - clang_dir, - ] + + # Determine suffixed output gen_snapshot name. + target_cpu_suffix = target_cpu if (target_cpu == "arm") { - args += [ - "--armv7-out-dir", - rebase_path("$root_out_dir"), - ] - outputs = [ "$host_output_dir/gen_snapshot_armv7" ] - } else { - args += [ - "--arm64-out-dir", - rebase_path("$root_out_dir"), - ] - outputs = [ "$host_output_dir/gen_snapshot_arm64" ] + target_cpu_suffix = "armv7" } + + input = "${host_output_dir}/gen_snapshot" + output = "${host_output_dir}/gen_snapshot_${target_cpu_suffix}" + deps = [ "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)" ] + visibility = [ ":*" ] } } +# Creates a `gen_snapshot` binary suffixed with the target CPU architecture. +# +# Builds gen_snapshot using the host toolchain then copies the resulting binary +# to `gen_snapshot_arm64` or `gen_snapshot_x64` depending on the target +# platform. +# +# This target is used for builds targeting macOS. if (host_os == "mac" && target_os == "mac") { - macos_gen_snapshots("create_macos_gen_snapshots") { - deps = [ ":generate_snapshot_bin" ] - arch = "$target_cpu" + strip_bitcode("create_macos_gen_snapshots") { + # The toolchain-specific output directory. For cross-compiles, this is a + # clang-x64 or clang-arm64 subdirectory of the top-level build directory. + host_output_dir = get_label_info( + "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", + "root_out_dir") + + input = "${host_output_dir}/gen_snapshot" + output = "${root_out_dir}/gen_snapshot_${target_cpu}" + deps = [ "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)" ] + metadata = { + snapshot_entitlement_file_path = [ "gen_snapshot_{$target_cpu}" ] + } } } diff --git a/lib/ui/geometry.dart b/lib/ui/geometry.dart index 23edb691d1fc3..9945ba8666898 100644 --- a/lib/ui/geometry.dart +++ b/lib/ui/geometry.dart @@ -634,7 +634,8 @@ class Size extends OffsetBase { class Rect { /// Construct a rectangle from its left, top, right, and bottom edges. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltrb.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltrb.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltrb_dark.png#gh-dark-mode-only) @pragma('vm:entry-point') const Rect.fromLTRB(this.left, this.top, this.right, this.bottom) : assert(left != null), @@ -648,14 +649,16 @@ class Rect { /// To construct a [Rect] from an [Offset] and a [Size], you can use the /// rectangle constructor operator `&`. See [Offset.&]. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltwh.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltwh.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_ltwh_dark.png#gh-dark-mode-only) const Rect.fromLTWH(double left, double top, double width, double height) : this.fromLTRB(left, top, left + width, top + height); /// Construct a rectangle that bounds the given circle. /// /// The `center` argument is assumed to be an offset from the origin. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_circle.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_circle.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_circle_dark.png#gh-dark-mode-only) Rect.fromCircle({ required Offset center, required double radius }) : this.fromCenter( center: center, width: radius * 2, @@ -666,7 +669,8 @@ class Rect { /// /// The `center` argument is assumed to be an offset from the origin. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_center.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_center.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_center_dark.png#gh-dark-mode-only) Rect.fromCenter({ required Offset center, required double width, required double height }) : this.fromLTRB( center.dx - width / 2, center.dy - height / 2, @@ -677,7 +681,8 @@ class Rect { /// Construct the smallest rectangle that encloses the given offsets, treating /// them as vectors from the origin. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_points.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_points.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/rect_from_points_dark.png#gh-dark-mode-only) Rect.fromPoints(Offset a, Offset b) : this.fromLTRB( math.min(a.dx, b.dx), math.min(a.dy, b.dy), @@ -934,12 +939,14 @@ class Rect { class Radius { /// Constructs a circular radius. [x] and [y] will have the same radius value. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_circular.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_circular.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_circular_dark.png#gh-dark-mode-only) const Radius.circular(double radius) : this.elliptical(radius, radius); /// Constructs an elliptical radius with the given radii. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_elliptical.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_elliptical.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/radius_elliptical_dark.png#gh-dark-mode-only) const Radius.elliptical(this.x, this.y); /// The radius value on the horizontal axis. diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a411a59ef9987..018060dfcdcee 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2430,7 +2430,8 @@ class Path extends NativeFieldWrapperClass1 { /// point to the given point (x2,y2), using the control point /// (x1,y1). /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_quadratic_to.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_quadratic_to.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_quadratic_to_dark.png#gh-dark-mode-only) @FfiNative, Float, Float, Float, Float)>('Path::quadraticBezierTo', isLeaf: true) external void quadraticBezierTo(double x1, double y1, double x2, double y2); @@ -2446,7 +2447,8 @@ class Path extends NativeFieldWrapperClass1 { /// to the given point (x3,y3), using the control points (x1,y1) and /// (x2,y2). /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_cubic_to.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_cubic_to.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_cubic_to_dark.png#gh-dark-mode-only) @FfiNative, Float, Float, Float, Float, Float, Float)>('Path::cubicTo', isLeaf: true) external void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3); @@ -2463,7 +2465,8 @@ class Path extends NativeFieldWrapperClass1 { /// hyperbola; if the weight equals 1, it's a parabola; and if it is /// less than 1, it is an ellipse. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_conic_to.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_conic_to.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_conic_to_dark.png#gh-dark-mode-only) @FfiNative, Float, Float, Float, Float, Float)>('Path::conicTo', isLeaf: true) external void conicTo(double x1, double y1, double x2, double y2, double w); @@ -2594,9 +2597,11 @@ class Path extends NativeFieldWrapperClass1 { /// rectangle and with positive angles going clockwise around the /// oval. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc_dark.png#gh-dark-mode-only) /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc_ccw.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc_ccw.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/path_add_arc_ccw_dark.png#gh-dark-mode-only) void addArc(Rect oval, double startAngle, double sweepAngle) { assert(_rectIsValid(oval)); _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle); @@ -4913,7 +4918,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// /// The `p1` and `p2` arguments are interpreted as offsets from the origin. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_line.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_line.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_line_dark.png#gh-dark-mode-only) void drawLine(Offset p1, Offset p2, Paint paint) { assert(_offsetIsValid(p1)); assert(_offsetIsValid(p2)); @@ -4939,7 +4945,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled /// or stroked (or both) is controlled by [Paint.style]. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rect.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rect.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rect_dark.png#gh-dark-mode-only) void drawRect(Rect rect, Paint paint) { assert(_rectIsValid(rect)); assert(paint != null); @@ -4952,7 +4959,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is /// filled or stroked (or both) is controlled by [Paint.style]. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rrect.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rrect.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_rrect_dark.png#gh-dark-mode-only) void drawRRect(RRect rrect, Paint paint) { assert(_rrectIsValid(rrect)); assert(paint != null); @@ -4981,7 +4989,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// with the given [Paint]. Whether the oval is filled or stroked (or both) is /// controlled by [Paint.style]. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_oval.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_oval.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_oval_dark.png#gh-dark-mode-only) void drawOval(Rect rect, Paint paint) { assert(_rectIsValid(rect)); assert(paint != null); @@ -4996,7 +5005,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// the third argument. Whether the circle is filled or stroked (or both) is /// controlled by [Paint.style]. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_circle.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_circle.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_circle_dark.png#gh-dark-mode-only) void drawCircle(Offset c, double radius, Paint paint) { assert(_offsetIsValid(c)); assert(paint != null); @@ -5016,7 +5026,8 @@ class Canvas extends NativeFieldWrapperClass1 { /// closed back to the center, forming a circle sector. Otherwise, the arc is /// not closed, forming a circle segment. /// - /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_draw_arc.png) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_draw_arc.png#gh-light-mode-only) + /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/canvas_draw_arc_dark.png#gh-dark-mode-only) /// /// This method is optimized for drawing arcs and should be faster than [Path.arcTo]. void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { diff --git a/lib/web_ui/dev/steps/run_tests_step.dart b/lib/web_ui/dev/steps/run_tests_step.dart index 97d6c8fbea299..38d733a1f9493 100644 --- a/lib/web_ui/dev/steps/run_tests_step.dart +++ b/lib/web_ui/dev/steps/run_tests_step.dart @@ -38,7 +38,7 @@ class RunTestsStep implements PipelineStep { required this.requireSkiaGold, this.testFiles, required this.overridePathToCanvasKit, - }) : _browserEnvironment = getBrowserEnvironment(browserName); + }); final String browserName; final List? testFiles; @@ -49,8 +49,6 @@ class RunTestsStep implements PipelineStep { /// Require Skia Gold to be available and reachable. final bool requireSkiaGold; - final BrowserEnvironment _browserEnvironment; - @override String get description => 'run_tests'; @@ -63,14 +61,16 @@ class RunTestsStep implements PipelineStep { @override Future run() async { await _prepareTestResultsDirectory(); - await _browserEnvironment.prepare(); + + final BrowserEnvironment browserEnvironment = getBrowserEnvironment(browserName); + await browserEnvironment.prepare(); final SkiaGoldClient? skiaClient = await _createSkiaClient(); final List testFiles = this.testFiles ?? findAllTests(); await _runTestBatch( testFiles: testFiles, - browserEnvironment: _browserEnvironment, + browserEnvironment: browserEnvironment, expectFailure: false, isDebug: isDebug, doUpdateScreenshotGoldens: doUpdateScreenshotGoldens, @@ -78,7 +78,7 @@ class RunTestsStep implements PipelineStep { overridePathToCanvasKit: overridePathToCanvasKit, ); - await _browserEnvironment.cleanup(); + await browserEnvironment.cleanup(); if (io.exitCode != 0) { throw ToolExit('Some tests failed'); diff --git a/lib/web_ui/dev/test_runner.dart b/lib/web_ui/dev/test_runner.dart index 8984d2f7b25b9..1a695c310258d 100644 --- a/lib/web_ui/dev/test_runner.dart +++ b/lib/web_ui/dev/test_runner.dart @@ -141,12 +141,30 @@ class TestCommand extends Command with ArgUtils { overridePathToCanvasKit: overridePathToCanvasKit, ), ]); - await testPipeline.run(); + + try { + await testPipeline.run(); + if (isWatchMode) { + print(''); + print('Initial test succeeded!'); + } + } catch(error, stackTrace) { + if (isWatchMode) { + // The error is printed but not rethrown in watch mode because + // failures are expected. The idea is that the developer corrects the + // error, saves the file, and the pipeline reruns. + print(''); + print('Initial test failed!\n'); + print(error); + print(stackTrace); + } else { + rethrow; + } + } if (isWatchMode) { final FilePath dir = FilePath.fromWebUi(''); print(''); - print('Initial test run is done!'); print( 'Watching ${dir.relativeToCwd}/lib and ${dir.relativeToCwd}/test to re-run tests'); print(''); diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 9e1f48e8bb189..a2e028a0e822d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -322,6 +322,11 @@ class HtmlViewEmbedder { clipView.style.clipPath = ''; headTransform = Matrix4.identity(); clipView.style.transform = ''; + // We need to set width and height for the clipView to cover the + // bounds of the path since Safari seem to incorrectly intersect + // the element bounding rect with the clip path. + clipView.style.width = '100%'; + clipView.style.height = '100%'; if (mutator.rect != null) { final ui.Rect rect = mutator.rect!; clipView.style.clip = 'rect(${rect.top}px, ${rect.right}px, ' diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index c74b547ee3654..fa067f049f8d3 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -591,7 +591,10 @@ class PlatformViewLayer extends Layer { @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { paintBounds = ui.Rect.fromLTWH(offset.dx, offset.dy, width, height); - prerollContext.viewEmbedder!.prerollCompositeEmbeddedView( + + /// ViewEmbedder is set to null when screenshotting. Therefore, skip + /// rendering + prerollContext.viewEmbedder?.prerollCompositeEmbeddedView( viewId, EmbeddedViewParams( offset, @@ -604,7 +607,7 @@ class PlatformViewLayer extends Layer { @override void paint(PaintContext paintContext) { final CkCanvas? canvas = - paintContext.viewEmbedder!.compositeEmbeddedView(viewId); + paintContext.viewEmbedder?.compositeEmbeddedView(viewId); if (canvas != null) { paintContext.leafNodesCanvas = canvas; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart index 83964c6f4222c..ad5b43e92a2ca 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart @@ -37,33 +37,16 @@ class NotoFont { // is a range that contains the codeunit. int min = 0; int max = _rangeStarts.length - 1; - // Search for the first rangeStart that is greater than codeunit. - while (min < max) { + while (min <= max) { final int mid = (min + max) ~/ 2; if (_rangeStarts[mid] > codeUnit) { - if (mid == 0) { - final int rangeStart = _rangeStarts[mid]; - final int rangeEnd = _rangeEnds[mid]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; - } - final int rangeStart = _rangeStarts[mid - 1]; - if (rangeStart <= codeUnit) { - final int rangeEnd = _rangeEnds[mid - 1]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; - } else { - max = mid - 1; - } - } else if (_rangeStarts[mid] < codeUnit) { - // If this is the last index, check if the codeunit is contained within it. - if (mid == _rangeStarts.length) { - final int rangeStart = _rangeStarts[mid]; - final int rangeEnd = _rangeEnds[mid]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; + max = mid - 1; + } else { + // _rangeStarts[mid] <= codeUnit + if (_rangeEnds[mid] >= codeUnit) { + return true; } min = mid + 1; - } else { - // _rangeStarts[mid] == codeUnit - return true; } } return false; diff --git a/lib/web_ui/lib/src/engine/html/color_filter.dart b/lib/web_ui/lib/src/engine/html/color_filter.dart index 8b6507a8a8553..3436f9837f9ae 100644 --- a/lib/web_ui/lib/src/engine/html/color_filter.dart +++ b/lib/web_ui/lib/src/engine/html/color_filter.dart @@ -52,6 +52,7 @@ class PersistedColorFilter extends PersistedContainerSurface void discard() { super.discard(); flutterViewEmbedder.removeResource(_filterElement); + _filterElement = null; // Do not detach the child container from the root. It is permanently // attached. The elements are reused together and are detached from the DOM // together. diff --git a/lib/web_ui/lib/src/engine/html/shader_mask.dart b/lib/web_ui/lib/src/engine/html/shader_mask.dart index c5dea3124b230..83988c294df09 100644 --- a/lib/web_ui/lib/src/engine/html/shader_mask.dart +++ b/lib/web_ui/lib/src/engine/html/shader_mask.dart @@ -57,6 +57,7 @@ class PersistedShaderMask extends PersistedContainerSurface void discard() { super.discard(); flutterViewEmbedder.removeResource(_shaderElement); + _shaderElement = null; // Do not detach the child container from the root. It is permanently // attached. The elements are reused together and are detached from the DOM // together. diff --git a/lib/web_ui/lib/src/engine/pointer_binding.dart b/lib/web_ui/lib/src/engine/pointer_binding.dart index a41b550c5fd8a..75ad7b4387d4d 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding.dart @@ -339,6 +339,13 @@ mixin _WheelEventListenerMixin on _BaseAdapter { deltaY *= ui.window.physicalSize.height; break; case domDeltaPixel: + if (operatingSystem == OperatingSystem.macOs && (isSafari || isFirefox)) { + // Safari and Firefox seem to report delta in logical pixels while + // Chrome uses physical pixels. + deltaX *= ui.window.devicePixelRatio; + deltaY *= ui.window.devicePixelRatio; + } + break; default: break; } diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 7cdb18c0120dd..e72bc0df0c6bb 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -95,6 +95,22 @@ void testMain() { .clipPath, 'url("#svgClip1")', ); + expect( + flutterViewEmbedder.sceneElement! + .querySelectorAll('flt-clip') + .single + .style + .width, + '100%', + ); + expect( + flutterViewEmbedder.sceneElement! + .querySelectorAll('flt-clip') + .single + .style + .height, + '100%', + ); }); test('correctly transforms platform views', () async { diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index 66ba97d7eb9fa..84c05602b8d69 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -199,6 +199,31 @@ void testMain() { expect(loggingDownloader.log, isEmpty); }); + test('can find glyph for 2/3 symbol', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; + final LoggingDownloader loggingDownloader = + LoggingDownloader(NotoDownloader()); + notoDownloadQueue.downloader = loggingDownloader; + // Try rendering text that requires fallback fonts, initially before the fonts are loaded. + + CkParagraphBuilder(CkParagraphStyle()).addText('â…”'); + rasterizer.debugRunPostFrameCallbacks(); + await notoDownloadQueue.debugWhenIdle(); + expect( + loggingDownloader.log, + [ + 'Noto Sans', + ], + ); + + // Do the same thing but this time with loaded fonts. + loggingDownloader.log.clear(); + CkParagraphBuilder(CkParagraphStyle()).addText('â…”'); + rasterizer.debugRunPostFrameCallbacks(); + await notoDownloadQueue.debugWhenIdle(); + expect(loggingDownloader.log, isEmpty); + }); + test('findMinimumFontsForCodeunits for all supported code units', () async { final LoggingDownloader loggingDownloader = LoggingDownloader(NotoDownloader()); @@ -213,9 +238,7 @@ void testMain() { for (final NotoFont font in notoTree.root.enumerateAllElements()) { testedFonts.add(font.name); for (final CodeunitRange range in font.computeUnicodeRanges()) { - for (int codeUnit = range.start; - codeUnit < range.end; - codeUnit += 1) { + for (int codeUnit = range.start; codeUnit < range.end; codeUnit++) { supportedUniqueCodeUnits.add(codeUnit); } } diff --git a/lib/web_ui/test/canvaskit/layer_test.dart b/lib/web_ui/test/canvaskit/layer_test.dart index b4bc7d866b953..d5f942dc0859b 100644 --- a/lib/web_ui/test/canvaskit/layer_test.dart +++ b/lib/web_ui/test/canvaskit/layer_test.dart @@ -52,5 +52,26 @@ void testMain() { recorder.beginRecording(ui.Rect.zero); LayerSceneBuilder().addPicture(ui.Offset.zero, recorder.endRecording()); }); + + test('null ViewEmbedder with PlatformView', () async { + final LayerSceneBuilder sb = LayerSceneBuilder(); + const ui.Rect kDefaultRegion = ui.Rect.fromLTRB(0, 0, 200, 200); + await createPlatformView(0, 'test-platform-view'); + sb.pushOffset(0, 0); + sb.addPlatformView(0, width: 10, height: 10); + sb.pushOffset(0, 0); + final LayerScene layerScene = sb.build(); + final ui.Image testImage = await layerScene.toImage(100, 100); + + final CkPictureRecorder recorder = CkPictureRecorder(); + final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); + canvas.drawImage(testImage as CkImage, ui.Offset.zero, CkPaint()); + await matchPictureGolden( + 'canvaskit_picture.png', + recorder.endRecording(), + region: kDefaultRegion, + ); + //https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox || isSafari); }); } diff --git a/lib/web_ui/test/engine/pointer_binding_test.dart b/lib/web_ui/test/engine/pointer_binding_test.dart index 44ff17a0017e9..130c53f33e740 100644 --- a/lib/web_ui/test/engine/pointer_binding_test.dart +++ b/lib/web_ui/test/engine/pointer_binding_test.dart @@ -6,11 +6,7 @@ import 'dart:js_util' as js_util; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine.dart' show flutterViewEmbedder, window; -import 'package:ui/src/engine/browser_detection.dart'; -import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/embedder.dart'; -import 'package:ui/src/engine/pointer_binding.dart'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; const int _kNoButtonChange = -1; @@ -43,7 +39,7 @@ void main() { void testMain() { ensureFlutterViewEmbedderInitialized(); final DomElement glassPane = flutterViewEmbedder.glassPaneElement!; - double dpi = 1.0; + late double dpi; setUp(() { ui.window.onPointerDataPacket = null; @@ -726,6 +722,104 @@ void testMain() { }, ); + _testEach<_ButtonedEventMixin>( + <_ButtonedEventMixin>[ + if (!isIosSafari) _PointerEventContext(), + if (!isIosSafari) _MouseEventContext(), + ], + 'converts scroll delta to physical pixels (Firefox)', + (_ButtonedEventMixin context) { + PointerBinding.instance!.debugOverrideDetector(context); + + const double dpi = 2.5; + debugOperatingSystemOverride = OperatingSystem.macOs; + debugBrowserEngineOverride = BrowserEngine.firefox; + window.debugOverrideDevicePixelRatio(dpi); + + final List packets = []; + ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) { + packets.add(packet); + }; + + glassPane.dispatchEvent(context.wheel( + buttons: 0, + clientX: 10, + clientY: 10, + deltaX: 10, + deltaY: 10, + )); + + expect(packets, hasLength(1)); + + + // An add will be synthesized. + expect(packets[0].data, hasLength(2)); + expect(packets[0].data[0].change, equals(ui.PointerChange.add)); + // Scroll deltas should be multiplied by `dpi`. + expect(packets[0].data[0].scrollDeltaX, equals(10.0 * dpi)); + expect(packets[0].data[0].scrollDeltaY, equals(10.0 * dpi)); + + expect(packets[0].data[1].change, equals(ui.PointerChange.hover)); + expect(packets[0].data[1].signalKind, equals(ui.PointerSignalKind.scroll)); + // Scroll deltas should be multiplied by `dpi`. + expect(packets[0].data[0].scrollDeltaX, equals(10.0 * dpi)); + expect(packets[0].data[0].scrollDeltaY, equals(10.0 * dpi)); + + window.debugOverrideDevicePixelRatio(1.0); + debugOperatingSystemOverride = null; + debugBrowserEngineOverride = null; + }, + ); + + _testEach<_ButtonedEventMixin>( + <_ButtonedEventMixin>[ + if (!isIosSafari) _PointerEventContext(), + if (!isIosSafari) _MouseEventContext(), + ], + 'scroll delta are already in physical pixels (Chrome)', + (_ButtonedEventMixin context) { + PointerBinding.instance!.debugOverrideDetector(context); + + const double dpi = 2.5; + debugOperatingSystemOverride = OperatingSystem.macOs; + debugBrowserEngineOverride = BrowserEngine.blink; + window.debugOverrideDevicePixelRatio(dpi); + + final List packets = []; + ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) { + packets.add(packet); + }; + + glassPane.dispatchEvent(context.wheel( + buttons: 0, + clientX: 10, + clientY: 10, + deltaX: 10, + deltaY: 10, + )); + + expect(packets, hasLength(1)); + + + // An add will be synthesized. + expect(packets[0].data, hasLength(2)); + expect(packets[0].data[0].change, equals(ui.PointerChange.add)); + // Scroll deltas should NOT be multiplied by `dpi`. + expect(packets[0].data[0].scrollDeltaX, equals(10.0)); + expect(packets[0].data[0].scrollDeltaY, equals(10.0)); + + expect(packets[0].data[1].change, equals(ui.PointerChange.hover)); + expect(packets[0].data[1].signalKind, equals(ui.PointerSignalKind.scroll)); + // Scroll deltas should NOT be multiplied by `dpi`. + expect(packets[0].data[0].scrollDeltaX, equals(10.0)); + expect(packets[0].data[0].scrollDeltaY, equals(10.0)); + + window.debugOverrideDevicePixelRatio(1.0); + debugOperatingSystemOverride = null; + debugBrowserEngineOverride = null; + }, + ); + _testEach<_ButtonedEventMixin>( <_ButtonedEventMixin>[ if (!isIosSafari) _PointerEventContext(), diff --git a/lib/web_ui/test/engine/surface/surface_test.dart b/lib/web_ui/test/engine/surface/surface_test.dart index 702ada6b5db38..5a57d85ed6c59 100644 --- a/lib/web_ui/test/engine/surface/surface_test.dart +++ b/lib/web_ui/test/engine/surface/surface_test.dart @@ -13,6 +13,10 @@ void main() { void testMain() { group('Surface', () { + setUpAll(() async { + await webOnlyInitializePlatform(); + }); + setUp(() { SurfaceSceneBuilder.debugForgetFrameScene(); }); @@ -375,8 +379,67 @@ void testMain() { expect(() => shape.apply(), returnsNormally); }); }); + + final Map layerFactories = { + 'ColorFilterEngineLayer': (SurfaceSceneBuilder builder) => builder.pushColorFilter(const ColorFilter.mode( + Color(0xFFFF0000), + BlendMode.srcIn, + )), + 'OffsetEngineLayer': (SurfaceSceneBuilder builder) => builder.pushOffset(1, 2), + 'TransformEngineLayer': (SurfaceSceneBuilder builder) => builder.pushTransform(Matrix4.identity().toFloat64()), + 'ClipRectEngineLayer': (SurfaceSceneBuilder builder) => builder.pushClipRect(const Rect.fromLTRB(0, 0, 10, 10)), + 'ClipRRectEngineLayer': (SurfaceSceneBuilder builder) => builder.pushClipRRect(RRect.fromRectXY(const Rect.fromLTRB(0, 0, 10, 10), 1, 2)), + 'ClipPathEngineLayer': (SurfaceSceneBuilder builder) => builder.pushClipPath(Path()..addRect(const Rect.fromLTRB(0, 0, 10, 10))), + 'OpacityEngineLayer': (SurfaceSceneBuilder builder) => builder.pushOpacity(100), + 'ImageFilterEngineLayer': (SurfaceSceneBuilder builder) => builder.pushImageFilter(ImageFilter.blur(sigmaX: 0.1, sigmaY: 0.2)), + 'BackdropEngineLayer': (SurfaceSceneBuilder builder) => builder.pushBackdropFilter(ImageFilter.blur(sigmaX: 0.1, sigmaY: 0.2)), + // Firefox does not support WebGL in headless mode. + if (!isFirefox) + 'ShaderMaskEngineLayer': (SurfaceSceneBuilder builder) { + const List colors = [Color(0xFF000000), Color(0xFFFF3C38)]; + const List stops = [0.0, 1.0]; + const Rect shaderBounds = Rect.fromLTWH(180, 10, 140, 140); + final EngineGradient shader = GradientLinear( + Offset(200 - shaderBounds.left, 30 - shaderBounds.top), + Offset(320 - shaderBounds.left, 150 - shaderBounds.top), + colors, stops, TileMode.clamp, Matrix4.identity().storage, + ); + return builder.pushShaderMask(shader, shaderBounds, BlendMode.srcOver); + }, + 'PhysicalShapeEngineLayer': (SurfaceSceneBuilder builder) => builder.pushPhysicalShape( + path: Path()..addRect(const Rect.fromLTRB(0, 0, 10, 10)), + elevation: 3, + color: const Color(0xAABBCCDD), + ), + }; + + // Regression test for https://github.com/flutter/flutter/issues/104305 + for (final MapEntry layerFactory in layerFactories.entries) { + test('${layerFactory.key} supports addRetained after being discarded', () async { + final SurfaceSceneBuilder builder = SurfaceSceneBuilder(); + builder.pushOffset(0, 0); + final PersistedSurface oldLayer = layerFactory.value(builder) as PersistedSurface; + builder.pop(); + builder.pop(); + builder.build(); + expect(oldLayer.isActive, isTrue); + + // Pump an empty frame so the `oldLayer` is discarded before it's reused. + final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder(); + builder2.build(); + expect(oldLayer.isReleased, isTrue); + + // At this point the `oldLayer` needs to be revived. + final SurfaceSceneBuilder builder3 = SurfaceSceneBuilder(); + builder3.addRetained(oldLayer); + builder3.build(); + expect(oldLayer.isActive, isTrue); + }); + } } +typedef TestEngineLayerFactory = EngineLayer Function(SurfaceSceneBuilder builder); + class _LoggingTestSurface extends PersistedContainerSurface { _LoggingTestSurface() : super(null); diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 169e83a268210..a6f7ab7159e5d 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -958,6 +958,8 @@ TEST(RasterizerTest, TeardownNoSurface) { } TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { + GTEST_SKIP() << "eglPresentationTime is disabled due to " + "https://github.com/flutter/flutter/issues/112503"; std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name(); ThreadHost thread_host("io.flutter.test." + test_name + ".", @@ -1042,6 +1044,8 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { } TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { + GTEST_SKIP() << "eglPresentationTime is disabled due to " + "https://github.com/flutter/flutter/issues/112503"; std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name(); ThreadHost thread_host("io.flutter.test." + test_name + ".", diff --git a/shell/platform/android/android_egl_surface.cc b/shell/platform/android/android_egl_surface.cc index fd0f4567dd53e..fa1573a6e25cc 100644 --- a/shell/platform/android/android_egl_surface.cc +++ b/shell/platform/android/android_egl_surface.cc @@ -193,14 +193,6 @@ AndroidEGLSurface::AndroidEGLSurface(EGLSurface surface, damage_(std::make_unique()), presentation_time_proc_(nullptr) { damage_->init(display_, context); - - const char* extensions = eglQueryString(display, EGL_EXTENSIONS); - - if (HasExtension(extensions, "EGL_ANDROID_presentation_time")) { - presentation_time_proc_ = - reinterpret_cast( - eglGetProcAddress("eglPresentationTimeANDROID")); - } } AndroidEGLSurface::~AndroidEGLSurface() { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 6a5f22b80a6dd..9c15b52f7d8ff 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -438,33 +438,20 @@ - (FlutterCompositor*)createFlutterCompositor { FlutterMetalRenderer* metalRenderer = reinterpret_cast(_renderer); _macOSCompositor = std::make_unique( _viewController, _platformViewController, metalRenderer.device); - _macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) { - FlutterMetalRenderer* metalRenderer = - reinterpret_cast(weakSelf.renderer); - if (has_flutter_content) { - return [metalRenderer present:0 /*=textureID*/] == YES; - } else { - [metalRenderer presentWithoutContent]; - return true; - } - }); } else { FlutterOpenGLRenderer* openGLRenderer = reinterpret_cast(_renderer); [openGLRenderer.openGLContext makeCurrentContext]; _macOSCompositor = std::make_unique(_viewController, openGLRenderer.openGLContext); - - _macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) { - FlutterOpenGLRenderer* openGLRenderer = - reinterpret_cast(weakSelf.renderer); - if (has_flutter_content) { - return [openGLRenderer glPresent] == YES; - } else { - [openGLRenderer presentWithoutContent]; - return true; - } - }); } + _macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) { + if (has_flutter_content) { + return [weakSelf.renderer present] == YES; + } else { + [weakSelf.renderer presentWithoutContent]; + return true; + } + }); _compositor = {}; _compositor.struct_size = sizeof(FlutterCompositor); diff --git a/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h b/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h index d820d7e438f71..7d44311ed491b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h @@ -29,16 +29,6 @@ */ - (FlutterMetalTexture)createTextureForSize:(CGSize)size; -/** - * Presents the texture specified by the texture id. - */ -- (BOOL)present:(int64_t)textureID; - -/** - * Tells the renderer that there is no Flutter content available for this frame. - */ -- (void)presentWithoutContent; - /** * Populates the texture registry with the provided metalTexture. */ diff --git a/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.mm index 2347d06fa098a..b7e0d0d65f281 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.mm @@ -20,8 +20,7 @@ static FlutterMetalTexture OnGetNextDrawable(FlutterEngine* engine, } static bool OnPresentDrawable(FlutterEngine* engine, const FlutterMetalTexture* texture) { - FlutterMetalRenderer* metalRenderer = reinterpret_cast(engine.renderer); - return [metalRenderer present:texture->texture_id]; + return [engine.renderer present]; } static bool OnAcquireExternalTexture(FlutterEngine* engine, @@ -36,8 +35,6 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine, #pragma mark - FlutterMetalRenderer implementation @implementation FlutterMetalRenderer { - __weak FlutterEngine* _engine; - FlutterView* _flutterView; FlutterDarwinContextMetal* _darwinMetalContext; @@ -46,8 +43,6 @@ @implementation FlutterMetalRenderer { - (instancetype)initWithFlutterEngine:(nonnull FlutterEngine*)flutterEngine { self = [super initWithDelegate:self engine:flutterEngine]; if (self) { - _engine = flutterEngine; - _device = MTLCreateSystemDefaultDevice(); if (!_device) { NSLog(@"Could not acquire Metal device."); @@ -99,7 +94,7 @@ - (FlutterMetalTexture)createTextureForSize:(CGSize)size { return embedderTexture; } -- (BOOL)present:(int64_t)textureID { +- (BOOL)present { if (!_flutterView) { return NO; } @@ -108,6 +103,9 @@ - (BOOL)present:(int64_t)textureID { } - (void)presentWithoutContent { + if (!_flutterView) { + return; + } [_flutterView presentWithoutContent]; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterMetalRendererTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterMetalRendererTest.mm index 346535db64e05..e045bf09c0d71 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterMetalRendererTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterMetalRendererTest.mm @@ -30,9 +30,9 @@ FlutterEngine* engine = CreateTestEngine(); FlutterMetalRenderer* renderer = [[FlutterMetalRenderer alloc] initWithFlutterEngine:engine]; id mockFlutterView = OCMClassMock([FlutterView class]); - [[mockFlutterView expect] present]; + [(FlutterView*)[mockFlutterView expect] present]; [renderer setFlutterView:mockFlutterView]; - [renderer present:1]; + [renderer present]; } TEST(FlutterMetalRenderer, TextureReturnedByFlutterView) { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h index cbc972b48d108..2d8bf08d90c08 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h @@ -34,16 +34,6 @@ */ - (BOOL)clearCurrent; -/** - * Called by the engine when the context's buffers should be swapped. - */ -- (BOOL)glPresent; - -/** - * Tells the renderer that there is no Flutter content available for this frame. - */ -- (void)presentWithoutContent; - /** * Called by the engine when framebuffer object ID is requested. */ diff --git a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm index 3c456cf744c04..9c694480d8421 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm @@ -20,8 +20,7 @@ static bool OnClearCurrent(FlutterEngine* engine) { } static bool OnPresent(FlutterEngine* engine) { - FlutterOpenGLRenderer* openGLRenderer = reinterpret_cast(engine.renderer); - return [openGLRenderer glPresent]; + return [engine.renderer present]; } static uint32_t OnFBO(FlutterEngine* engine, const FlutterFrameInfo* info) { @@ -56,15 +55,10 @@ @implementation FlutterOpenGLRenderer { // The context provided to the Flutter engine for resource loading. NSOpenGLContext* _resourceContext; - - __weak FlutterEngine* _flutterEngine; } - (instancetype)initWithFlutterEngine:(FlutterEngine*)flutterEngine { self = [super initWithDelegate:self engine:flutterEngine]; - if (self) { - _flutterEngine = flutterEngine; - } return self; } @@ -88,15 +82,18 @@ - (BOOL)clearCurrent { return true; } -- (BOOL)glPresent { - if (!_openGLContext) { - return false; +- (BOOL)present { + if (!_openGLContext || !_flutterView) { + return NO; } [_flutterView present]; - return true; + return YES; } - (void)presentWithoutContent { + if (!_flutterView) { + return; + } [_flutterView presentWithoutContent]; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm index df53d94dcae70..808e32686dd6c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm @@ -113,10 +113,10 @@ - (nullable instancetype)initWithGLRenderer { FlutterEngine* engine = [[TestOpenGLEngine alloc] initWithGLRenderer]; FlutterOpenGLRenderer* renderer = [[FlutterOpenGLRenderer alloc] initWithFlutterEngine:engine]; id mockFlutterView = OCMClassMock([FlutterView class]); - [[mockFlutterView expect] present]; + [(FlutterView*)[mockFlutterView expect] present]; [renderer setFlutterView:mockFlutterView]; [renderer openGLContext]; - [renderer glPresent]; + [renderer present]; } TEST(FlutterOpenGLRenderer, FBOReturnedByFlutterView) { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h index 2a67333d071dd..8f88964b38c60 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h @@ -29,4 +29,14 @@ */ - (FlutterRendererConfig)createRendererConfig; +/** + * Called by the engine when the context's buffers should be swapped. + */ +- (BOOL)present; + +/** + * Tells the renderer that there is no Flutter content available for this frame. + */ +- (void)presentWithoutContent; + @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index a4c37b179607f..bf13f616782f6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -611,7 +611,7 @@ - (void)dispatchMouseEvent:(NSEvent*)event phase:(FlutterPointerPhase)phase { } else if (event.type == NSEventTypeMagnify) { _mouseState.scale += event.magnification; } else if (event.type == NSEventTypeRotate) { - _mouseState.rotation += event.rotation * (M_PI / 180.0); + _mouseState.rotation += event.rotation * (-M_PI / 180.0); } flutterEvent.pan_x = _mouseState.delta_x; flutterEvent.pan_y = _mouseState.delta_y; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 09e047ce15478..5905600b6d1e4 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -33,6 +33,25 @@ + (void)respondFalseForSendEvent:(const FlutterKeyEvent&)event namespace { +id MockGestureEvent(NSEventType type, NSEventPhase phase, double magnification, double rotation) { + id event = [OCMockObject mockForClass:[NSEvent class]]; + NSPoint locationInWindow = NSMakePoint(0, 0); + CGFloat deltaX = 0; + CGFloat deltaY = 0; + NSTimeInterval timestamp = 1; + NSUInteger modifierFlags = 0; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(phase)] phase]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(locationInWindow)] locationInWindow]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaX)] deltaX]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaY)] deltaY]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(timestamp)] timestamp]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(magnification)] magnification]; + [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(rotation)] rotation]; + return event; +} + // Allocates and returns an engine configured for the test fixture resource configuration. FlutterEngine* CreateTestEngine() { NSString* fixtures = @(testing::GetFixturesPath()); @@ -432,6 +451,7 @@ - (bool)testTrackpadGesturesAreSentToFramework { bundle:nil]; [viewController loadView]; + // Test for pan events. // Start gesture. CGEventRef cgEventStart = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0); CGEventSetType(cgEventStart, kCGEventScrollWheel); @@ -566,6 +586,106 @@ - (bool)testTrackpadGesturesAreSentToFramework { EXPECT_EQ(last_event.scroll_delta_x, -40 * viewController.flutterView.layer.contentsScale); EXPECT_EQ(last_event.scroll_delta_y, -80 * viewController.flutterView.layer.contentsScale); + // Test for scale events. + // Start gesture. + called = false; + [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify, + NSEventPhaseBegan, 1, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomStart); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + + // Update gesture. + called = false; + [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify, + NSEventPhaseChanged, 1, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomUpdate); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.pan_x, 0); + EXPECT_EQ(last_event.pan_y, 0); + EXPECT_EQ(last_event.scale, 2); // macOS uses logarithmic scaling values, the linear value for + // flutter here should be 2^1 = 2. + EXPECT_EQ(last_event.rotation, 0); + + // Make sure the scale values accumulate. + called = false; + [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify, + NSEventPhaseChanged, 1, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomUpdate); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.pan_x, 0); + EXPECT_EQ(last_event.pan_y, 0); + EXPECT_EQ(last_event.scale, 4); // macOS uses logarithmic scaling values, the linear value for + // flutter here should be 2^(1+1) = 2. + EXPECT_EQ(last_event.rotation, 0); + + // End gesture. + called = false; + [viewController magnifyWithEvent:flutter::testing::MockGestureEvent(NSEventTypeMagnify, + NSEventPhaseEnded, 0, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomEnd); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + + // Test for rotation events. + // Start gesture. + called = false; + [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate, + NSEventPhaseBegan, 1, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomStart); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + + // Update gesture. + called = false; + [viewController rotateWithEvent:flutter::testing::MockGestureEvent( + NSEventTypeRotate, NSEventPhaseChanged, 0, -180)]; // degrees + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomUpdate); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.pan_x, 0); + EXPECT_EQ(last_event.pan_y, 0); + EXPECT_EQ(last_event.scale, 1); + EXPECT_EQ(last_event.rotation, M_PI); // radians + + // Make sure the rotation values accumulate. + called = false; + [viewController rotateWithEvent:flutter::testing::MockGestureEvent( + NSEventTypeRotate, NSEventPhaseChanged, 0, -360)]; // degrees + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomUpdate); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.pan_x, 0); + EXPECT_EQ(last_event.pan_y, 0); + EXPECT_EQ(last_event.scale, 1); + EXPECT_EQ(last_event.rotation, 3 * M_PI); // radians + + // End gesture. + called = false; + [viewController rotateWithEvent:flutter::testing::MockGestureEvent(NSEventTypeRotate, + NSEventPhaseEnded, 0, 0)]; + EXPECT_TRUE(called); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + EXPECT_EQ(last_event.phase, kPanZoomEnd); + EXPECT_EQ(last_event.device_kind, kFlutterPointerDeviceKindTrackpad); + EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindNone); + return true; } diff --git a/shell/platform/fuchsia/dart_runner/BUILD.gn b/shell/platform/fuchsia/dart_runner/BUILD.gn index 85350bd3929e2..87520ce524e0c 100644 --- a/shell/platform/fuchsia/dart_runner/BUILD.gn +++ b/shell/platform/fuchsia/dart_runner/BUILD.gn @@ -298,6 +298,20 @@ jit_runner_package("dart_jit_product_runner") { product = true } +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +aot_runner_package("oot_dart_aot_runner") { + product = false +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +jit_runner_package("oot_dart_jit_runner") { + product = false +} + if (enable_unittests) { runner_sources("jit_runner_sources_for_test") { product = false diff --git a/shell/platform/fuchsia/dart_runner/tests/README.md b/shell/platform/fuchsia/dart_runner/tests/README.md index 0bfb005e5fc6c..2509a19baafb1 100644 --- a/shell/platform/fuchsia/dart_runner/tests/README.md +++ b/shell/platform/fuchsia/dart_runner/tests/README.md @@ -1,40 +1,3 @@ # Dart Runner Tests Contains tests for the Dart Runner and their corresponding utility code - -### Running the Tests - -- The tests can be run using the Fuchsia emulator -``` -fx set workstation_eng.qemu-x64 -ffx emu start --headless -``` -- Start up the package server -``` -fx serve -``` -- Prepare the BUILD files -``` -$ENGINE_DIR/flutter/tools/gn --fuchsia --no-lto -``` -- Build the Fuchsia binary with the test directory as the target (ie. `flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test`) -``` -ninja -C $ENGINE_DIR/out/fuchsia_debug_x64 flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test -``` -- Deploy/publish test FAR files to Fuchsia -``` -$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_debug_x64/dart-jit-runner-integration-test-0.far -``` - -Note that some tests may have components that also need to be deployed/published (ie. `dart_jit_echo_server` also needs to be published for the Dart JIT integration test to run successfully) - -``` -$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_debug_x64/gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/dart_jit_echo_server/dart_jit_echo_server.far -``` -- Run the test -``` -ffx test run "fuchsia-pkg://fuchsia.com/dart-jit-runner-integration-test#meta/dart-jit-runner-integration-test.cm" -``` - -Notes: -- To find the FAR files, `ls` into the output directory provided to the `ninja` command diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/BUILD.gn b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/BUILD.gn index 3ce01796bbc88..efb1d7ac29647 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/BUILD.gn +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/BUILD.gn @@ -6,5 +6,8 @@ import("//build/fuchsia/sdk.gni") group("startup_integration_test") { testonly = true - deps = [ "dart_jit_runner:tests" ] + deps = [ + "dart_aot_runner:tests", + "dart_jit_runner:tests", + ] } diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/BUILD.gn b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/BUILD.gn new file mode 100644 index 0000000000000..43e68bab0ccdd --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/BUILD.gn @@ -0,0 +1,47 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/fuchsia/sdk.gni") + +import("//flutter/tools/fuchsia/dart/dart_component.gni") +import("//flutter/tools/fuchsia/fidl/fidl.gni") +import("//flutter/tools/fuchsia/fuchsia_archive.gni") + +group("tests") { + testonly = true + deps = [ ":dart-aot-runner-integration-test" ] +} + +executable("dart-aot-runner-integration-test-bin") { + testonly = true + + output_name = "dart-aot-runner-integration-test" + + sources = [ "dart-aot-runner-integration-test.cc" ] + + # This is needed for //third_party/googletest for linking zircon symbols. + libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] + + deps = [ + "$fuchsia_sdk_root/fidl:fuchsia.logger", + "$fuchsia_sdk_root/fidl:fuchsia.tracing.provider", + "$fuchsia_sdk_root/pkg:async", + "$fuchsia_sdk_root/pkg:async-loop-testing", + "$fuchsia_sdk_root/pkg:fidl_cpp", + "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + "//flutter/shell/platform/fuchsia/dart_runner/tests/fidl/flutter.example.echo:echo", + "//flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server:aot_echo_package", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + ] +} + +fuchsia_test_archive("dart-aot-runner-integration-test") { + deps = [ ":dart-aot-runner-integration-test-bin" ] + + binary = "$target_name" + cml_file = rebase_path("meta/$target_name.cml") +} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/README.md b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/README.md new file mode 100644 index 0000000000000..53184dc437218 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/README.md @@ -0,0 +1,36 @@ +# dart_aot_runner + +Contains the integration test for the Dart AOT runner. + +### Running Tests + +#### Setup emulator and PM serve +``` +fx set workstation_eng.qemu-x64 +ffx emu start --headless + +fx serve +``` + +#### Prepare build files and build binary +``` +$ENGINE_DIR/flutter/tools/gn --fuchsia --no-lto --runtime-mode=profile +ninja -C $ENGINE_DIR/out/fuchsia_profile_x64 flutter/shell/platform/fuchsia fuchsia_tests +``` + +#### Publish files to PM +``` +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_profile_x64/dart-aot-runner-integration-test-0.far + +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_profile_x64/oot_dart_aot_runner-0.far + +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_profile_x64/gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/dart_aot_echo_server/dart_aot_echo_server.far +``` + +#### Run test +``` +ffx test run "fuchsia-pkg://fuchsia.com/dart-aot-runner-integration-test#meta/dart-aot-runner-integration-test.cm" +``` + +## Notes +The `profile` runtime should be used when running the `dart_aot_runner` integration test. Snapshots will fail to generate or generate incorrectly if the wrong runtime is used. diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart-aot-runner-integration-test.cc b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart-aot-runner-integration-test.cc new file mode 100644 index 0000000000000..fff8d443e0315 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart-aot-runner-integration-test.cc @@ -0,0 +1,112 @@ +// 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. + +// The generated C++ bindings for the Echo FIDL protocol +#include + +#include + +#include +#include +#include + +#include "flutter/fml/logging.h" +#include "gtest/gtest.h" + +namespace dart_aot_runner_testing::testing { +namespace { + +// Types imported for the realm_builder library +using component_testing::ChildOptions; +using component_testing::ChildRef; +using component_testing::Directory; +using component_testing::ParentRef; +using component_testing::Protocol; +using component_testing::RealmBuilder; +using component_testing::RealmRoot; +using component_testing::Route; + +constexpr auto kDartRunnerEnvironment = "dart_runner_env"; + +constexpr auto kDartAotRunner = "dart_aot_runner"; +constexpr auto kDartAotRunnerRef = ChildRef{kDartAotRunner}; +constexpr auto kDartAotRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_dart_aot_runner#meta/" + "dart_aot_runner.cm"; + +constexpr auto kDartAotEchoServer = "dart_aot_echo_server"; +constexpr auto kDartAotEchoServerRef = ChildRef{kDartAotEchoServer}; +constexpr auto kDartAotEchoServerUrl = + "fuchsia-pkg://fuchsia.com/dart_aot_echo_server#meta/" + "dart_aot_echo_server.cm"; + +class RealmBuilderTest : public ::loop_fixture::RealLoop, + public ::testing::Test { + public: + RealmBuilderTest() = default; +}; + +TEST_F(RealmBuilderTest, DartRunnerStartsUp) { + auto realm_builder = RealmBuilder::Create(); + // Add Dart AOT runner as a child of RealmBuilder + realm_builder.AddChild(kDartAotRunner, kDartAotRunnerUrl); + + // Add environment providing the Dart AOT runner + fuchsia::component::decl::Environment dart_runner_environment; + dart_runner_environment.set_name(kDartRunnerEnvironment); + dart_runner_environment.set_extends( + fuchsia::component::decl::EnvironmentExtends::REALM); + dart_runner_environment.set_runners({}); + auto environment_runners = dart_runner_environment.mutable_runners(); + + fuchsia::component::decl::RunnerRegistration dart_aot_runner_reg; + dart_aot_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kDartAotRunner})); + dart_aot_runner_reg.set_source_name(kDartAotRunner); + dart_aot_runner_reg.set_target_name(kDartAotRunner); + environment_runners->push_back(std::move(dart_aot_runner_reg)); + + auto realm_decl = realm_builder.GetRealmDecl(); + if (!realm_decl.has_environments()) { + realm_decl.set_environments({}); + } + auto realm_environments = realm_decl.mutable_environments(); + realm_environments->push_back(std::move(dart_runner_environment)); + realm_builder.ReplaceRealmDecl(std::move(realm_decl)); + + // Add Dart server component as a child of Realm Builder + realm_builder.AddChild(kDartAotEchoServer, kDartAotEchoServerUrl, + ChildOptions{.environment = kDartRunnerEnvironment}); + + // Route base capabilities to the Dart AOT runner + realm_builder.AddRoute( + Route{.capabilities = {Protocol{"fuchsia.logger.LogSink"}, + Protocol{"fuchsia.tracing.provider.Registry"}, + Protocol{"fuchsia.posix.socket.Provider"}, + Protocol{"fuchsia.intl.PropertyProvider"}, + Protocol{"fuchsia.vulkan.loader.Loader"}, + Directory{"config-data"}}, + .source = ParentRef(), + .targets = {kDartAotRunnerRef, kDartAotEchoServerRef}}); + + // Route the Echo FIDL protocol, this allows the Dart echo server to + // communicate with the Realm Builder + realm_builder.AddRoute( + Route{.capabilities = {Protocol{"flutter.example.echo.Echo"}}, + .source = kDartAotEchoServerRef, + .targets = {ParentRef()}}); + + // Build the Realm with the provided child and protocols + auto realm = realm_builder.Build(dispatcher()); + FML_LOG(INFO) << "Realm built: " << realm.GetChildName(); + // Connect to the Dart echo server + auto echo = realm.ConnectSync(); + fidl::StringPtr response; + // Attempt to ping the Dart echo server for a response + echo->EchoString("hello", &response); + ASSERT_EQ(response, "hello"); +} + +} // namespace +} // namespace dart_aot_runner_testing::testing diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/dart-aot-runner-integration-test.cml b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/dart-aot-runner-integration-test.cml new file mode 100644 index 0000000000000..9ef643ec9a9c6 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/dart-aot-runner-integration-test.cml @@ -0,0 +1,40 @@ +// 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: [ + "gtest_runner.shard.cml", + "sys/component/realm_builder_absolute.shard.cml", + + // This test needs both the vulkan facet and the hermetic-tier-2 facet, + // so we are forced to make it a system test. + "sys/testing/system-test.shard.cml", + ], + program: { + binary: "bin/app", + }, + offer: [ + { + // Offer capabilities needed by components in this test realm. + // Keep it minimal, describe only what's actually needed. + protocol: [ + "fuchsia.logger.LogSink", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.vulkan.loader.Loader", + "fuchsia.posix.socket.Provider", + "fuchsia.intl.PropertyProvider", + ], + from: "parent", + to: "#realm_builder", + }, + { + directory: "pkg", + subdir: "config", + as: "config-data", + from: "framework", + to: "#realm_builder", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/gtest_runner.shard.cml b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/gtest_runner.shard.cml new file mode 100644 index 0000000000000..f6cfe507747ad --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/meta/gtest_runner.shard.cml @@ -0,0 +1,18 @@ +// 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. + +{ + program: { + runner: "gtest_runner", + }, + capabilities: [ + { protocol: "fuchsia.test.Suite" }, + ], + expose: [ + { + protocol: "fuchsia.test.Suite", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/BUILD.gn b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/BUILD.gn new file mode 100644 index 0000000000000..c6b7622ca9b9f --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/BUILD.gn @@ -0,0 +1,78 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/fuchsia/sdk.gni") + +import("//flutter/tools/fuchsia/dart/dart_component.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + testonly = true + package_name = "dart_echo_server" + null_safe = true + + source_dir = "." + sources = [ "main.dart" ] + + deps = [ + "//flutter/shell/platform/fuchsia/dart_runner/tests/fidl/flutter.example.echo:echo", + "//flutter/tools/fuchsia/dart:fidl", + "//flutter/tools/fuchsia/dart:fuchsia_services", + "//flutter/tools/fuchsia/fidl:fuchsia.logger", + "//flutter/tools/fuchsia/fidl:fuchsia.test", + ] +} + +# Dart component that serves the test Echo FIDL protocol, built using the Dart AOT runner +dart_component("aot_component") { + testonly = true + null_safe = true + + main_package = "dart_echo_server" + manifest = "meta/dart-aot-echo-server.cml" + component_name = "dart_aot_echo_server" + + deps = [ ":lib" ] +} + +# Dart component that serves the test Echo FIDL protocol, built using the Dart AOT runner +dart_component("jit_component") { + testonly = true + null_safe = true + + main_package = "dart_echo_server" + manifest = "meta/dart-jit-echo-server.cml" + component_name = "dart_jit_echo_server" + + deps = [ ":lib" ] +} + +fuchsia_package("aot_echo_package") { + testonly = true + + package_name = "dart_aot_echo_server" + deps = [ + ":aot_component", + + # "OOT" copy of the runner used by tests, to avoid conflicting with the + # runners in the base fuchsia image. + # TODO(fxbug.dev/106575): Fix this with subpackages. + "//flutter/shell/platform/fuchsia/dart_runner:oot_dart_aot_runner", + ] +} + +fuchsia_package("jit_echo_package") { + testonly = true + + package_name = "dart_jit_echo_server" + deps = [ + ":jit_component", + + # "OOT" copy of the runner used by tests, to avoid conflicting with the + # runners in the base fuchsia image. + # TODO(fxbug.dev/106575): Fix this with subpackages. + "//flutter/shell/platform/fuchsia/dart_runner:oot_dart_jit_runner", + ] +} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md new file mode 100644 index 0000000000000..4d2e098a69ec7 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md @@ -0,0 +1,7 @@ +# dart_echo_server + +Contains the Echo servers for the integration tests. There are currently two outputs: +- `dart-aot-echo-server` +- `dart-jit-ehco-server` + +The outputs run with their respective Dart runners and are consumed by their respective integration test. \ No newline at end of file diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/main.dart b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/main.dart similarity index 100% rename from shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/main.dart rename to shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/main.dart diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-aot-echo-server.cml b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-aot-echo-server.cml new file mode 100644 index 0000000000000..8f9954f736dd9 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-aot-echo-server.cml @@ -0,0 +1,21 @@ +// 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: [ "syslog/client.shard.cml" ], + program: { + data: "data/dart-aot-echo-server", + runner: "dart_aot_runner", + }, + // Capabilities provided by this component. + capabilities: [ + { protocol: "flutter.example.echo.Echo" }, + ], + expose: [ + { + protocol: "flutter.example.echo.Echo", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/meta/dart-jit-echo-server.cml b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-jit-echo-server.cml similarity index 92% rename from shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/meta/dart-jit-echo-server.cml rename to shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-jit-echo-server.cml index 7d5d684507154..9687045f14285 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/meta/dart-jit-echo-server.cml +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/meta/dart-jit-echo-server.cml @@ -5,6 +5,7 @@ { include: [ "syslog/client.shard.cml" ], program: { + data: "data/dart-jit-echo-server", runner: "dart_jit_runner", }, // Capabilities provided by this component. diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/BUILD.gn b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/BUILD.gn index d918de9415f4c..b464b3f0213ef 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/BUILD.gn +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/BUILD.gn @@ -31,19 +31,16 @@ executable("dart-jit-runner-integration-test-bin") { "$fuchsia_sdk_root/pkg:fidl_cpp", "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", "$fuchsia_sdk_root/pkg:zx", - "dart_jit_echo_server:package", "//flutter/fml", "//flutter/shell/platform/fuchsia/dart_runner/tests/fidl/flutter.example.echo:echo", + "//flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server:jit_echo_package", "//third_party/googletest:gtest", "//third_party/googletest:gtest_main", ] } fuchsia_test_archive("dart-jit-runner-integration-test") { - deps = [ - ":dart-jit-runner-integration-test-bin", - "dart_jit_echo_server:package", - ] + deps = [ ":dart-jit-runner-integration-test-bin" ] binary = "$target_name" cml_file = rebase_path("meta/$target_name.cml") diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/README.md b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/README.md index be30e687b3fd6..98b52069f1dfa 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/README.md +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/README.md @@ -1,3 +1,36 @@ # dart_jit_runner -Contains the integration test for the Dart JIT runner. The Dart Echo server is launched with a JIT runner. +Contains the integration test for the Dart JIT runner. + +### Running Tests + +#### Setup emulator and PM serve +``` +fx set workstation_eng.qemu-x64 +ffx emu start --headless + +fx serve +``` + +#### Prepare build files and build binary +``` +$ENGINE_DIR/flutter/tools/gn --fuchsia --no-lto +ninja -C $ENGINE_DIR/out/fuchsia_debug_x64 flutter/shell/platform/fuchsia fuchsia_tests +``` + +#### Publish files to PM +``` +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_debug_x64/dart-jit-runner-integration-test-0.far + +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_debug_x64/oot_dart_jit_runner-0.far + +$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/fuchsia_debug_x64/gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/dart_jit_echo_server/dart_jit_echo_server.far +``` + +#### Run test +``` +ffx test run "fuchsia-pkg://fuchsia.com/dart-jit-runner-integration-test#meta/dart-jit-runner-integration-test.cm" +``` + +## Notes +The `debug` runtime should be used when running the `dart_jit_runner` integration test. Snapshots will fail to generate or generate incorrectly if the wrong runtime is used. diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart-jit-runner-integration-test.cc b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart-jit-runner-integration-test.cc index b7d61132e36fd..0c24533459e11 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart-jit-runner-integration-test.cc +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart-jit-runner-integration-test.cc @@ -5,6 +5,8 @@ // The generated C++ bindings for the Echo FIDL protocol #include +#include + #include #include #include @@ -15,13 +17,30 @@ namespace dart_jit_runner_testing::testing { namespace { +// Types imported for the realm_builder library +using component_testing::ChildOptions; using component_testing::ChildRef; +using component_testing::Directory; using component_testing::ParentRef; using component_testing::Protocol; using component_testing::RealmBuilder; using component_testing::RealmRoot; using component_testing::Route; +constexpr auto kDartRunnerEnvironment = "dart_runner_env"; + +constexpr auto kDartJitRunner = "dart_jit_runner"; +constexpr auto kDartJitRunnerRef = ChildRef{kDartJitRunner}; +constexpr auto kDartJitRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_dart_jit_runner#meta/" + "dart_jit_runner.cm"; + +constexpr auto kDartJitEchoServer = "dart_jit_echo_server"; +constexpr auto kDartJitEchoServerRef = ChildRef{kDartJitEchoServer}; +constexpr auto kDartJitEchoServerUrl = + "fuchsia-pkg://fuchsia.com/dart_jit_echo_server#meta/" + "dart_jit_echo_server.cm"; + class RealmBuilderTest : public ::loop_fixture::RealLoop, public ::testing::Test { public: @@ -30,20 +49,52 @@ class RealmBuilderTest : public ::loop_fixture::RealLoop, TEST_F(RealmBuilderTest, DartRunnerStartsUp) { auto realm_builder = RealmBuilder::Create(); + // Add Dart JIT runner as a child of RealmBuilder + realm_builder.AddChild(kDartJitRunner, kDartJitRunnerUrl); + + // Add environment providing the Dart JIT runner + fuchsia::component::decl::Environment dart_runner_environment; + dart_runner_environment.set_name(kDartRunnerEnvironment); + dart_runner_environment.set_extends( + fuchsia::component::decl::EnvironmentExtends::REALM); + dart_runner_environment.set_runners({}); + auto environment_runners = dart_runner_environment.mutable_runners(); + + fuchsia::component::decl::RunnerRegistration dart_jit_runner_reg; + dart_jit_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kDartJitRunner})); + dart_jit_runner_reg.set_source_name(kDartJitRunner); + dart_jit_runner_reg.set_target_name(kDartJitRunner); + environment_runners->push_back(std::move(dart_jit_runner_reg)); + auto realm_decl = realm_builder.GetRealmDecl(); + if (!realm_decl.has_environments()) { + realm_decl.set_environments({}); + } + auto realm_environments = realm_decl.mutable_environments(); + realm_environments->push_back(std::move(dart_runner_environment)); + realm_builder.ReplaceRealmDecl(std::move(realm_decl)); + // Add Dart server component as a child of Realm Builder - realm_builder.AddChild("hello_world", - "fuchsia-pkg://fuchsia.com/dart_jit_echo_server#meta/" - "dart_jit_echo_server.cm"); + realm_builder.AddChild(kDartJitEchoServer, kDartJitEchoServerUrl, + ChildOptions{.environment = kDartRunnerEnvironment}); + + // Route base capabilities to the Dart JIT runner realm_builder.AddRoute( - Route{.capabilities = {Protocol{"fuchsia.logger.LogSink"}}, + Route{.capabilities = {Protocol{"fuchsia.logger.LogSink"}, + Protocol{"fuchsia.tracing.provider.Registry"}, + Protocol{"fuchsia.posix.socket.Provider"}, + Protocol{"fuchsia.intl.PropertyProvider"}, + Directory{"config-data"}}, .source = ParentRef(), - .targets = {ChildRef{"hello_world"}}}); + .targets = {kDartJitRunnerRef, kDartJitEchoServerRef}}); + // Route the Echo FIDL protocol, this allows the Dart echo server to // communicate with the Realm Builder realm_builder.AddRoute( Route{.capabilities = {Protocol{"flutter.example.echo.Echo"}}, - .source = ChildRef{"hello_world"}, + .source = kDartJitEchoServerRef, .targets = {ParentRef()}}); + // Build the Realm with the provided child and protocols auto realm = realm_builder.Build(dispatcher()); FML_LOG(INFO) << "Realm built: " << realm.GetChildName(); diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/BUILD.gn b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/BUILD.gn deleted file mode 100644 index bf5bc016ab6b6..0000000000000 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/BUILD.gn +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/fuchsia/sdk.gni") - -import("//flutter/tools/fuchsia/dart/dart_component.gni") -import("//flutter/tools/fuchsia/dart/dart_library.gni") -import("//flutter/tools/fuchsia/gn-sdk/package.gni") - -dart_library("lib") { - testonly = true - package_name = "dart_jit_echo_server" - null_safe = true - - source_dir = "." - sources = [ "main.dart" ] - - deps = [ - "//flutter/shell/platform/fuchsia/dart_runner/tests/fidl/flutter.example.echo:echo", - "//flutter/tools/fuchsia/dart:fidl", - "//flutter/tools/fuchsia/dart:fuchsia_services", - "//flutter/tools/fuchsia/fidl:fuchsia.logger", - "//flutter/tools/fuchsia/fidl:fuchsia.test", - ] -} - -# Dart component that serves the test Echo FIDL protocol, built using the Dart JIT runner -dart_component("component") { - testonly = true - null_safe = true - - manifest = "meta/dart-jit-echo-server.cml" - main_package = "dart_jit_echo_server" - component_name = "dart_jit_echo_server" - - deps = [ ":lib" ] -} - -fuchsia_package("package") { - testonly = true - - package_name = "dart_jit_echo_server" - deps = [ ":component" ] -} diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/meta/dart-jit-runner-integration-test.cml b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/meta/dart-jit-runner-integration-test.cml index af47353d2835e..9ef643ec9a9c6 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/meta/dart-jit-runner-integration-test.cml +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/meta/dart-jit-runner-integration-test.cml @@ -23,9 +23,18 @@ "fuchsia.sysmem.Allocator", "fuchsia.tracing.provider.Registry", "fuchsia.vulkan.loader.Loader", + "fuchsia.posix.socket.Provider", + "fuchsia.intl.PropertyProvider", ], from: "parent", to: "#realm_builder", }, + { + directory: "pkg", + subdir: "config", + as: "config-data", + from: "framework", + to: "#realm_builder", + }, ], } diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index be43799f7a775..c2538feb3a22f 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -104,8 +104,7 @@ void FlatlandExternalViewEmbedder::BeginFrame( // Reset for new frame. Reset(); frame_size_ = frame_size; - - // TODO(fxbug.dev/94000): Handle device pixel ratio. + frame_dpr_ = device_pixel_ratio; // Create the root layer. frame_layers_.emplace( @@ -180,6 +179,10 @@ void FlatlandExternalViewEmbedder::SubmitFrame( { TRACE_EVENT0("flutter", "SubmitLayers"); + // First re-scale everything according to the DPR. + const float inv_dpr = 1.0f / frame_dpr_; + flatland_->flatland()->SetScale(root_transform_id_, {inv_dpr, inv_dpr}); + size_t flatland_layer_index = 0; for (const auto& layer_id : frame_composition_order_) { const auto& layer = frame_layers_.find(layer_id); @@ -463,6 +466,7 @@ void FlatlandExternalViewEmbedder::Reset() { frame_layers_.clear(); frame_composition_order_.clear(); frame_size_ = SkISize::Make(0, 0); + frame_dpr_ = 1.f; // Clear all children from root. for (const auto& transform : child_transforms_) { diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index b7019be4f5b56..a32e66fa4ff4d 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -190,6 +190,7 @@ class FlatlandExternalViewEmbedder final std::vector frame_composition_order_; std::vector child_transforms_; SkISize frame_size_ = SkISize::Make(0, 0); + float frame_dpr_ = 1.f; FML_DISALLOW_COPY_AND_ASSIGN(FlatlandExternalViewEmbedder); }; diff --git a/shell/platform/fuchsia/flutter/flatland_platform_view.cc b/shell/platform/fuchsia/flutter/flatland_platform_view.cc index af7b9ee35fb99..6b9a5dfbd6517 100644 --- a/shell/platform/fuchsia/flutter/flatland_platform_view.cc +++ b/shell/platform/fuchsia/flutter/flatland_platform_view.cc @@ -75,10 +75,16 @@ void FlatlandPlatformView::OnGetLayout( view_logical_size_ = {static_cast(info.logical_size().width), static_cast(info.logical_size().height)}; - // TODO(fxbug.dev/94000): Set device pixel ratio. + float pixel_ratio = 1.0f; + if (info.has_device_pixel_ratio()) { + // Flatland returns a Vec2 for DPR but both values should be identical. + FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y); + view_pixel_ratio_ = info.device_pixel_ratio().x; + pixel_ratio = *view_pixel_ratio_; + } SetViewportMetrics({ - 1, // device_pixel_ratio + pixel_ratio, // device_pixel_ratio view_logical_size_.value()[0], // physical_width view_logical_size_.value()[1], // physical_height 0.0f, // physical_padding_top diff --git a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc index 0298537cc24bf..fac48844c782e 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc @@ -211,7 +211,8 @@ Matcher IsFlutterGraph( parent_viewport_watcher, const fuchsia::ui::views::ViewportCreationToken& viewport_creation_token, const fuchsia::ui::views::ViewRef& view_ref, - std::vector>> layer_matchers = {}) { + std::vector>> layer_matchers = {}, + fuchsia::math::VecF scale = FakeTransform::kDefaultScale) { auto viewport_token_koids = GetKoids(viewport_creation_token); auto view_ref_koids = GetKoids(view_ref); auto watcher_koids = GetKoids(parent_viewport_watcher); @@ -220,7 +221,7 @@ Matcher IsFlutterGraph( /*content_map*/ _, /*transform_map*/ _, Pointee(FieldsAre( /*id*/ _, FakeTransform::kDefaultTranslation, - FakeTransform::kDefaultScale, FakeTransform::kDefaultOrientation, + /*scale*/ scale, FakeTransform::kDefaultOrientation, /*clip_bounds*/ _, FakeTransform::kDefaultOpacity, /*children*/ ElementsAreArray(layer_matchers), /*content*/ Eq(nullptr), /*num_hit_regions*/ _)), @@ -524,7 +525,7 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { const int kOpacity = 200; const float kOpacityFloat = 200 / 255.0f; - const fuchsia::math::VecF kScale{0.5f, 0.9f}; + const fuchsia::math::VecF kScale{3.0f, 4.0f}; auto matrix = SkMatrix::I(); matrix.setScaleX(kScale.x); @@ -550,13 +551,17 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { child_view_id, child_view_occlusion_hint, /*hit_testable=*/false, /*focusable=*/false); + // We must take into account the effect of DPR on the view scale. + const float kDPR = 2.0f; + const float kInvDPR = 1.f / kDPR; + // Draw the scene. The scene graph shouldn't change yet. const SkISize frame_size_signed = SkISize::Make(512, 512); const fuchsia::math::SizeU frame_size{ static_cast(frame_size_signed.width()), static_cast(frame_size_signed.height())}; DrawFrameWithView( - external_view_embedder, frame_size_signed, 1.f, child_view_id, + external_view_embedder, frame_size_signed, kDPR, child_view_id, child_view_params, [](SkCanvas* canvas) { const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(), @@ -588,6 +593,7 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { loop().RunUntilIdle(); fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u)); loop().RunUntilIdle(); + EXPECT_THAT( fake_flatland().graph(), IsFlutterGraph( @@ -595,7 +601,8 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)})); + IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + {kInvDPR, kInvDPR})); // Destroy the view. The scene graph shouldn't change yet. external_view_embedder.DestroyView( @@ -607,7 +614,8 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)})); + IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + {kInvDPR, kInvDPR})); // Draw another frame without the view. The scene graph shouldn't change yet. DrawSimpleFrame( @@ -629,7 +637,8 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { {IsImageLayer(frame_size, kFirstLayerBlendMode, 1), IsViewportLayer(child_view_token, child_view_size, child_view_inset, {0, 0}, kScale, kOpacityFloat), - IsImageLayer(frame_size, kUpperLayerBlendMode, 1)})); + IsImageLayer(frame_size, kUpperLayerBlendMode, 1)}, + {kInvDPR, kInvDPR})); // Pump the message loop. The scene updates should propagate to flatland. loop().RunUntilIdle(); diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index be5b4e32f1d5b..cde88fd84d0d4 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -290,11 +290,14 @@ class MockParentViewportWatcher } } - void SetLayout(uint32_t logical_size_x, uint32_t logical_size_y) { + void SetLayout(uint32_t logical_size_x, + uint32_t logical_size_y, + float DPR = 1.0) { ::fuchsia::math::SizeU logical_size; logical_size.width = logical_size_x; logical_size.height = logical_size_y; layout_.set_logical_size(logical_size); + layout_.set_device_pixel_ratio({DPR, DPR}); if (pending_callback_valid_) { pending_layout_callback_(std::move(layout_)); @@ -649,6 +652,7 @@ TEST_F(FlatlandPlatformViewTests, CreateSurfaceTest) { // MetricsEvents sent to it via FIDL, correctly parses the metrics it receives, // and calls the SetViewportMetrics callback with the appropriate parameters. TEST_F(FlatlandPlatformViewTests, SetViewportMetrics) { + constexpr float kDPR = 2; constexpr uint32_t width = 640; constexpr uint32_t height = 480; @@ -665,10 +669,10 @@ TEST_F(FlatlandPlatformViewTests, SetViewportMetrics) { RunLoopUntilIdle(); EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); - watcher.SetLayout(width, height); + watcher.SetLayout(width, height, kDPR); RunLoopUntilIdle(); EXPECT_EQ(delegate.metrics(), - flutter::ViewportMetrics(1.0, width, height, -1.0)); + flutter::ViewportMetrics(kDPR, width, height, -1.0)); } // This test makes sure that the PlatformView correctly registers semantics diff --git a/shell/platform/fuchsia/unit_tests.md b/shell/platform/fuchsia/unit_tests.md index 1cd20a5a5b5e7..938ba1b772a9b 100644 --- a/shell/platform/fuchsia/unit_tests.md +++ b/shell/platform/fuchsia/unit_tests.md @@ -30,3 +30,9 @@ $ENGINE_DIR/flutter/tools/fuchsia/devshell/run_unit_tests.sh ```sh $ENGINE_DIR/flutter/tools/fuchsia/devshell/run_unit_tests.sh --package-filter flow_tests-0.far ``` + +- Pass `--gtest-filter` to run specific tests from the test package instead of all the tests. For example: + + ```sh + $ENGINE_DIR/flutter/tools/fuchsia/devshell/run_unit_tests.sh --package-filter flutter_runner_tests-0.far --gtest-filter "*FlatlandConnection*" + ``` diff --git a/sky/tools/create_macos_gen_snapshots.py b/sky/tools/create_macos_gen_snapshots.py index be93ced17d457..4603bcd1c2abe 100755 --- a/sky/tools/create_macos_gen_snapshots.py +++ b/sky/tools/create_macos_gen_snapshots.py @@ -82,21 +82,9 @@ def generate_gen_snapshot(directory, destination): print('Cannot find gen_snapshot at %s' % gen_snapshot_dir) sys.exit(1) - command = [ + subprocess.check_call([ 'xcrun', 'bitcode_strip', '-r', gen_snapshot_dir, '-o', destination - ] - process = subprocess.Popen( - command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE - ) - stdout, stderr = process.communicate() - exit_status = process.wait() - - if exit_status != 0: - print( - 'Error processing command with stdout[%s] and stderr[%s]' % - (stdout, stderr) - ) - return 1 + ]) if __name__ == '__main__': diff --git a/sky/tools/gen_snapshots.py b/sky/tools/gen_snapshots.py deleted file mode 100755 index 3dde468131fbe..0000000000000 --- a/sky/tools/gen_snapshots.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import argparse -import subprocess -import sys -import os - - -def main(): - parser = argparse.ArgumentParser( - description='Copies architecture-dependent gen_snapshot binaries to output dir' - ) - - parser.add_argument('--dst', type=str, required=True) - parser.add_argument('--out-dir', type=str) - parser.add_argument('--arch', type=str) - - args = parser.parse_args() - - subdir = '' - if args.arch != 'x64': - subdir = 'clang_x64' - - generate_gen_snapshot( - os.path.join(args.out_dir, subdir), - os.path.join(args.dst, 'gen_snapshot_%s' % args.arch) - ) - - -def generate_gen_snapshot(directory, destination): - gen_snapshot_dir = os.path.join(directory, 'gen_snapshot') - if not os.path.isfile(gen_snapshot_dir): - print('Cannot find gen_snapshot at %s' % gen_snapshot_dir) - sys.exit(1) - - subprocess.check_call([ - 'xcrun', 'bitcode_strip', '-r', gen_snapshot_dir, '-o', destination - ]) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sky/tools/macos.gni b/sky/tools/macos.gni new file mode 100644 index 0000000000000..f321dda68aba2 --- /dev/null +++ b/sky/tools/macos.gni @@ -0,0 +1,41 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//flutter/common/config.gni") + +# Copies an input macOS binary to the specified output path. Bitcode segments, +# if any, are stripped. +# +# Example: +# +# strip_bitcode( +# input = "$root_build_dir/gen_snapshot" +# output = "$root_build_dir/gen_snapshot_arm64" +# deps = [ ":gen_snapshot" ] +# ) +# +# TODO(cbracken): https://github.com/flutter/flutter/issues/107884 +# When we stop building with bitcode enabled, this template and the +# strip_bitcode.py script can be deleted and users can call copy() instead. +template("strip_bitcode") { + assert(defined(invoker.input), "The input to strip_bitcode must be defined") + assert(defined(invoker.output), "The output to strip_bitcode most be defined") + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "metadata", + "visibility", + ]) + script = "//flutter/sky/tools/strip_bitcode.py" + args = [ + "--input", + rebase_path(invoker.input), + "--output", + rebase_path(invoker.output), + ] + inputs = [ invoker.input ] + outputs = [ invoker.output ] + } +} diff --git a/sky/tools/macos_snapshots.gni b/sky/tools/macos_snapshots.gni deleted file mode 100644 index cc624c20bb923..0000000000000 --- a/sky/tools/macos_snapshots.gni +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//flutter/common/config.gni") - -# Generates macos gen snapshots $root_build_dir/zip_archives folder. -# - -# The output variable specifies the name of the zip file to create. -# The files variable is an array of scopes that specify a source file or -# directory and a destination path in the archive to create. -# -# For example, to create a zip file named archive.zip with all files in the -# root directory of the archive: -# -# zip_bundle("sample") { -# output = "archive.zip" -# files = [ -# { -# source = "$root_build_dir/some/path/to/lib.so" -# destination = "lib.so" -# }, -# { -# source = "$root_build_dir/some/other/path/with/files" -# destination = "other_files" -# }, -# ] -# } -template("macos_gen_snapshots") { - action(target_name) { - forward_variables_from(invoker, [ "visibility" ]) - deps = invoker.deps - outputs = [ "$root_build_dir/gen_snapshot_${invoker.arch}" ] - script = "//flutter/sky/tools/gen_snapshots.py" - args = [ - "--dst", - rebase_path("$root_out_dir/"), - "--out-dir", - rebase_path("$root_out_dir"), - "--arch", - invoker.arch, - ] - metadata = { - snapshot_entitlement_file_path = [ "gen_snapshot_${invoker.arch}" ] - } - } -} diff --git a/sky/tools/strip_bitcode.py b/sky/tools/strip_bitcode.py new file mode 100755 index 0000000000000..c5786ad5610fe --- /dev/null +++ b/sky/tools/strip_bitcode.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser( + description='Copies an input macOS binary to the specified output path. ' + 'Bitcode segments, if any, are stripped.' + ) + parser.add_argument( + '--input', + type=str, + required=True, + help='path of input binary to be read' + ) + parser.add_argument( + '--output', + type=str, + required=True, + help='path of output binary to be written' + ) + args = parser.parse_args() + + # Verify input binary exists. + if not os.path.isfile(args.input): + print('Cannot find input binary at %s' % args.input) + sys.exit(1) + + # Copy input path to output path. Strip bitcode segments, if any. + subprocess.check_call([ + 'xcrun', 'bitcode_strip', '-r', args.input, '-o', args.output + ]) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/testing/fuchsia/test_suites.yaml b/testing/fuchsia/test_suites.yaml index 711b7eff700a4..f3c985ec78d4b 100644 --- a/testing/fuchsia/test_suites.yaml +++ b/testing/fuchsia/test_suites.yaml @@ -39,6 +39,12 @@ package: dart_utils_tests-0.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart-jit-runner-integration-test#meta/dart-jit-runner-integration-test.cm packages: + - oot_dart_jit_runner-0.far - dart-jit-runner-integration-test-0.far - - dart_jit_runner-0.far - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/dart_jit_echo_server/dart_jit_echo_server.far +- test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart-aot-runner-integration-test#meta/dart-aot-runner-integration-test.cm + run_with_dart_aot: 'true' + packages: + - oot_dart_aot_runner-0.far + - dart-aot-runner-integration-test-0.far + - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart_aot_echo_server/dart_aot_echo_server/dart_aot_echo_server.far diff --git a/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc b/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc index 6cd3740a2a0b0..90d5e40156d0f 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc +++ b/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc @@ -271,6 +271,7 @@ void AXPlatformNodeWinTest::TearDown() { ax_fragment_root_.reset(nullptr); DestroyTree(); TestAXNodeWrapper::SetGlobalIsWebContent(false); + TestAXNodeWrapper::ClearHitTestResults(); ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting()); } @@ -446,8 +447,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleDetachedObject) { EXPECT_EQ(E_FAIL, root_obj->get_accName(SELF, name2.Receive())); } -// TODO(cbracken): Flaky https://github.com/flutter/flutter/issues/98302 -TEST_F(AXPlatformNodeWinTest, DISABLED_IAccessibleHitTest) { +TEST_F(AXPlatformNodeWinTest, IAccessibleHitTest) { AXNodeData root; root.id = 1; root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40); diff --git a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc index 6ed39a7bbc1dd..7270b83911da4 100644 --- a/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc +++ b/third_party/accessibility/ax/platform/test_ax_node_wrapper.cc @@ -119,6 +119,11 @@ void TestAXNodeWrapper::SetHitTestResult(AXNode::AXID src_node_id, g_hit_test_result[src_node_id] = dst_node_id; } +// static +void TestAXNodeWrapper::ClearHitTestResults() { + g_hit_test_result.clear(); +} + TestAXNodeWrapper::~TestAXNodeWrapper() { platform_node_->Destroy(); } diff --git a/third_party/accessibility/ax/platform/test_ax_node_wrapper.h b/third_party/accessibility/ax/platform/test_ax_node_wrapper.h index fc0581c12fd63..c2e9c208da872 100644 --- a/third_party/accessibility/ax/platform/test_ax_node_wrapper.h +++ b/third_party/accessibility/ax/platform/test_ax_node_wrapper.h @@ -56,6 +56,9 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase { static void SetHitTestResult(AXNode::AXID src_node_id, AXNode::AXID dst_node_id); + // Remove all hit test overrides added by SetHitTestResult. + static void ClearHitTestResults(); + ~TestAXNodeWrapper() override; AXPlatformNode* ax_platform_node() const { return platform_node_; } diff --git a/tools/clang_tidy/lib/clang_tidy.dart b/tools/clang_tidy/lib/clang_tidy.dart index 58f9a6ee20bde..b1af4486dde48 100644 --- a/tools/clang_tidy/lib/clang_tidy.dart +++ b/tools/clang_tidy/lib/clang_tidy.dart @@ -47,6 +47,7 @@ class ClangTidy { required io.File buildCommandsPath, String checksArg = '', bool lintAll = false, + bool lintHead = false, bool fix = false, StringSink? outSink, StringSink? errSink, @@ -55,6 +56,7 @@ class ClangTidy { buildCommandsPath: buildCommandsPath, checksArg: checksArg, lintAll: lintAll, + lintHead: lintHead, fix: fix, errSink: errSink, ), @@ -159,7 +161,15 @@ class ClangTidy { .whereType() .toList(); } - return GitRepo(options.repoPath).changedFiles; + + final GitRepo repo = GitRepo( + options.repoPath, + verbose: options.verbose, + ); + if (options.lintHead) { + return repo.changedFilesAtHead; + } + return repo.changedFiles; } /// Given a build commands json file, and the files with local changes, diff --git a/tools/clang_tidy/lib/src/git_repo.dart b/tools/clang_tidy/lib/src/git_repo.dart index b39769b684349..49d55a442efc1 100644 --- a/tools/clang_tidy/lib/src/git_repo.dart +++ b/tools/clang_tidy/lib/src/git_repo.dart @@ -10,7 +10,12 @@ import 'package:process_runner/process_runner.dart'; /// Utility methods for working with a git repo. class GitRepo { /// The git repository rooted at `root`. - GitRepo(this.root); + GitRepo(this.root, { + this.verbose = false, + }); + + /// Whether to produce verbose log output. + final bool verbose; /// The root of the git repo. final io.Directory root; @@ -26,23 +31,18 @@ class GitRepo { Future> get changedFiles async => _changedFiles ??= await _getChangedFiles(); + List? _changedFilesAtHead; + + /// Returns a list of non-deleted files which differ between the HEAD + /// commit and its parent. + Future> get changedFilesAtHead async => + _changedFilesAtHead ??= await _getChangedFilesAtHead(); + Future> _getChangedFiles() async { final ProcessRunner processRunner = ProcessRunner( defaultWorkingDirectory: root, ); - final ProcessRunnerResult fetchResult = await processRunner.runProcess( - ['git', 'fetch', 'upstream', 'main'], - failOk: true, - ); - if (fetchResult.exitCode != 0) { - await processRunner.runProcess([ - 'git', - 'fetch', - 'origin', - 'main', - ]); - } - final Set result = {}; + await _fetch(processRunner); ProcessRunnerResult mergeBaseResult = await processRunner.runProcess( ['git', 'merge-base', '--fork-point', 'FETCH_HEAD', 'HEAD'], failOk: true, @@ -64,10 +64,53 @@ class GitRepo { '--diff-filter=ACMRT', mergeBase, ]); - result.addAll(masterResult.stdout.split('\n').where( + return _gitOutputToList(masterResult); + } + + Future> _getChangedFilesAtHead() async { + final ProcessRunner processRunner = ProcessRunner( + defaultWorkingDirectory: root, + ); + await _fetch(processRunner); + final ProcessRunnerResult diffTreeResult = await processRunner.runProcess( + [ + 'git', + 'diff-tree', + '--no-commit-id', + '--name-only', + '--diff-filter=ACMRT', // Added, copied, modified, renamed, or type-changed. + '-r', + 'HEAD', + ], + ); + return _gitOutputToList(diffTreeResult); + } + + Future _fetch(ProcessRunner processRunner) async { + final ProcessRunnerResult fetchResult = await processRunner.runProcess( + ['git', 'fetch', 'upstream', 'main'], + failOk: true, + ); + if (fetchResult.exitCode != 0) { + await processRunner.runProcess([ + 'git', + 'fetch', + 'origin', + 'main', + ]); + } + } + + List _gitOutputToList(ProcessRunnerResult result) { + final String diffOutput = result.stdout.trim(); + if (verbose) { + print('git diff output:\n$diffOutput'); + } + final Set resultMap = {}; + resultMap.addAll(diffOutput.split('\n').where( (String str) => str.isNotEmpty, )); - return result.map( + return resultMap.map( (String filePath) => io.File(path.join(root.path, filePath)), ).toList(); } diff --git a/tools/clang_tidy/lib/src/options.dart b/tools/clang_tidy/lib/src/options.dart index a73dbc5d8086c..1b07bcf0deb37 100644 --- a/tools/clang_tidy/lib/src/options.dart +++ b/tools/clang_tidy/lib/src/options.dart @@ -20,6 +20,7 @@ class Options { this.verbose = false, this.checksArg = '', this.lintAll = false, + this.lintHead = false, this.fix = false, this.errorMessage, StringSink? errSink, @@ -60,6 +61,7 @@ class Options { checksArg: options.wasParsed('checks') ? options['checks'] as String : '', lintAll: io.Platform.environment['FLUTTER_LINT_ALL'] != null || options['lint-all'] as bool, + lintHead: options['lint-head'] as bool, fix: options['fix'] as bool, errSink: errSink, ); @@ -104,7 +106,11 @@ class Options { ) ..addFlag( 'lint-all', - help: 'lint all of the sources, regardless of FLUTTER_NOLINT.', + help: 'Lint all of the sources, regardless of FLUTTER_NOLINT.', + ) + ..addFlag( + 'lint-head', + help: 'Lint files changed in the tip-of-tree commit.', ) ..addFlag( 'fix', @@ -163,6 +169,9 @@ class Options { /// Whether all files should be linted. final bool lintAll; + /// Whether to lint only files changed in the tip-of-tree commit. + final bool lintHead; + /// Whether checks should apply available fix-ups to the working copy. final bool fix; @@ -178,7 +187,8 @@ class Options { _errSink.writeln(message); } _errSink.writeln( - 'Usage: bin/main.dart [--help] [--lint-all] [--fix] [--verbose] [--diff-branch] [--target-variant variant] [--src-dir path/to/engine/src]', + 'Usage: bin/main.dart [--help] [--lint-all] [--lint-head] [--fix] [--verbose] ' + '[--diff-branch] [--target-variant variant] [--src-dir path/to/engine/src]', ); _errSink.writeln(_argParser.usage); } @@ -198,6 +208,10 @@ class Options { return 'ERROR: --compile-commands option cannot be used with --src-dir.'; } + if (argResults.wasParsed('lint-all') && argResults.wasParsed('lint-head')) { + return 'ERROR: At most one of --lint-all and --lint-head can be passed.'; + } + if (!buildCommandsPath.existsSync()) { return "ERROR: Build commands path ${buildCommandsPath.absolute.path} doesn't exist."; } diff --git a/tools/clang_tidy/test/clang_tidy_test.dart b/tools/clang_tidy/test/clang_tidy_test.dart index b96c5a307a218..76e8eeab820a0 100644 --- a/tools/clang_tidy/test/clang_tidy_test.dart +++ b/tools/clang_tidy/test/clang_tidy_test.dart @@ -128,6 +128,29 @@ Future main(List args) async { )); }); + test('Error when --lint-all and --lint-head are used together', () async { + final StringBuffer outBuffer = StringBuffer(); + final StringBuffer errBuffer = StringBuffer(); + final ClangTidy clangTidy = ClangTidy.fromCommandLine( + [ + '--compile-commands', + '/unused', + '--lint-all', + '--lint-head', + ], + outSink: outBuffer, + errSink: errBuffer, + ); + + final int result = await clangTidy.run(); + + expect(clangTidy.options.help, isFalse); + expect(result, equals(1)); + expect(errBuffer.toString(), contains( + 'ERROR: At most one of --lint-all and --lint-head can be passed.', + )); + }); + test('lintAll=true checks all files', () async { final StringBuffer outBuffer = StringBuffer(); final StringBuffer errBuffer = StringBuffer(); diff --git a/tools/fuchsia/build_fuchsia_artifacts.py b/tools/fuchsia/build_fuchsia_artifacts.py index 302f9bf5e04d1..fe5dff51f9dcc 100755 --- a/tools/fuchsia/build_fuchsia_artifacts.py +++ b/tools/fuchsia/build_fuchsia_artifacts.py @@ -444,9 +444,20 @@ def main(): 'and copy two debug builds, one with ASAN and one without.' ) + # TODO(http://fxb/110639): Deprecate this in favor of multiple runtime parameters + parser.add_argument( + '--skip-remove-buckets', + action='store_true', + default=False, + help='This allows for multiple runtimes to exist in the default bucket directory. If ' + 'set, will skip over the removal of existing artifacts in the bucket directory ' + '(which is the default behavior).' + ) + args = parser.parse_args() - RemoveDirectoryIfExists(_bucket_directory) build_mode = args.runtime_mode + if (not args.skip_remove_buckets): + RemoveDirectoryIfExists(_bucket_directory) archs = ['x64', 'arm64'] if args.archs == 'all' else [args.archs] runtime_modes = ['debug', 'profile', 'release'] diff --git a/tools/fuchsia/devshell/run_unit_tests.sh b/tools/fuchsia/devshell/run_unit_tests.sh index 736d6e50e4d51..30364cb28c26d 100755 --- a/tools/fuchsia/devshell/run_unit_tests.sh +++ b/tools/fuchsia/devshell/run_unit_tests.sh @@ -7,6 +7,9 @@ ### ### Arguments: ### --package-filter: Only runs tests in packages that match the given `find` statement. +### --gtest-filter: In the packages, only runs tests that match the given filter. +### For example: --gtest-filter "*FlatlandConnection*" to run any tests +### that have the phrase FlatlandConnection in them. ### --unoptimized: Disables C++ compiler optimizations. ### --count: Number of times to run the test. By default runs 1 time. ### See `ffx test run --count`. @@ -27,19 +30,20 @@ goma=0 goma_flags="" ninja_cmd="ninja" package_filter="*tests-0.far" +test_filter_flags="" unoptimized_flags="" unoptimized_suffix="" -count_flag="" +count_flags="" while [[ $# -gt 0 ]]; do case $1 in - --package-filter) + --package_filter|--package-filter) shift # past argument package_filter="$1" shift # past value ;; --count) shift # past argument - count_flag="--count $1" + count_flags="--count $1" shift # past value ;; --goma) @@ -53,6 +57,11 @@ while [[ $# -gt 0 ]]; do unoptimized_suffix="_unopt" shift # past argument ;; + --gtest_filter|--gtest-filter) + shift # past argument + test_filter_flags="-- --gtest_filter=$1" + shift # past value + ;; *) engine-error "Unknown argument: $1" exit 1 @@ -98,7 +107,8 @@ do engine-warning "Skipping txt_tests because I don't know how to filter out ParagraphTests.*" continue fi - test_cmd="${FUCHSIA_DIR}/.jiri_root/bin/ffx test run fuchsia-pkg://fuchsia.com/${test_name}#meta/${test_name}.cm ${count_flag}" + # ${test_filter_flags} must come last below because it includes " -- " to start program arguments. + test_cmd="${FUCHSIA_DIR}/.jiri_root/bin/ffx test run fuchsia-pkg://fuchsia.com/${test_name}#meta/${test_name}.cm ${count_flags} ${test_filter_flags}" engine-info "... $test_cmd ..." $test_cmd diff --git a/tools/fuchsia/devshell/test/test_run_unit_tests.sh b/tools/fuchsia/devshell/test/test_run_unit_tests.sh new file mode 100755 index 0000000000000..adba2f1488e1f --- /dev/null +++ b/tools/fuchsia/devshell/test/test_run_unit_tests.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +### Tests run_unit_tests.sh by running it with various arguments. +### This script doesn't assert the results but just checks that the script runs +### successfully every time. +### +### This script doesn't run on CQ, it's only used for local testing. + +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $? + +ensure_engine_dir + +set -e # Fail on any error. + +engine-info "Testing run_unit_tests.sh --package-filter flutter_runner_tests-0.far..." +"$ENGINE_DIR"/flutter/tools/fuchsia/devshell/run_unit_tests.sh --package-filter "flutter_runner_tests-0.far" + +engine-info "Testing run_unit_tests.sh --package-filter flutter_runner_tests-0.far --count 2..." +"$ENGINE_DIR"/flutter/tools/fuchsia/devshell/run_unit_tests.sh --package-filter "flutter_runner_tests-0.far" --count 2 + + +engine-info "Testing run_unit_tests.sh --package-filter flutter_runner_tests-0.far --gtest-filter *FlatlandConnection*..." +"$ENGINE_DIR"/flutter/tools/fuchsia/devshell/run_unit_tests.sh --package-filter "flutter_runner_tests-0.far" --gtest-filter "*FlatlandConnection*" + +engine-info "Testing run_unit_tests.sh with no args..." +"$ENGINE_DIR"/flutter/tools/fuchsia/devshell/run_unit_tests.sh + diff --git a/web_sdk/sdk_rewriter.dart b/web_sdk/sdk_rewriter.dart index cb383b6a37433..617375e0eb9eb 100644 --- a/web_sdk/sdk_rewriter.dart +++ b/web_sdk/sdk_rewriter.dart @@ -211,14 +211,7 @@ String validateApiFile(String apiFilePath, String apiFileCode, String libraryNam } String preprocessPartFile(String source, String libraryName) { - if (source.startsWith('part of $libraryName;') || source.contains('\npart of $libraryName;')) { - // The file hasn't been migrated yet. - // Do nothing. - } else { - // Insert the part directive at the beginning of the file. - source = 'part of $libraryName;\n$source'; - } - return source; + return 'part of $libraryName;\n$source'; } /// Responsible for performing string replacements. diff --git a/web_sdk/test/sdk_rewriter_test.dart b/web_sdk/test/sdk_rewriter_test.dart index 22a424a66c36c..52cacc9e5306b 100644 --- a/web_sdk/test/sdk_rewriter_test.dart +++ b/web_sdk/test/sdk_rewriter_test.dart @@ -113,31 +113,6 @@ part of dart._engine; -void printSomething() { - print('something'); -} -'''; - - final String result = processSource( - source, - (String source) => preprocessPartFile(source, 'engine'), - generatePartsPatterns('engine'), - ); - expect(result, expected); - }); - - test('does not insert an extra part directive', () { - const String source = ''' -part of engine; - -void printSomething() { - print('something'); -} -'''; - - const String expected = ''' -part of dart._engine; - void printSomething() { print('something'); } From d1a614b8aa5fe3523804589cc17bee8a4cb57cd2 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 18:23:30 +0000 Subject: [PATCH 2/6] Lint merged files --- impeller/tessellator/tessellator_unittests.cc | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/impeller/tessellator/tessellator_unittests.cc b/impeller/tessellator/tessellator_unittests.cc index 73528f2b93561..96859cd05699d 100644 --- a/impeller/tessellator/tessellator_unittests.cc +++ b/impeller/tessellator/tessellator_unittests.cc @@ -10,56 +10,54 @@ namespace impeller { namespace testing { -TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) { - // Zero points. - { - Tessellator t; - auto polyline = PathBuilder{}.TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); +TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus){// Zero points. + {Tessellator t; +auto polyline = PathBuilder{}.TakePath().CreatePolyline(); +Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + +ASSERT_EQ(polyline.points.size(), 0u); +ASSERT_EQ(result, Tessellator::Result::kInputError); +} // namespace testing - ASSERT_EQ(polyline.points.size(), 0u); - ASSERT_EQ(result, Tessellator::Result::kInputError); - } +// One point. +{ + Tessellator t; + auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - // One point. - { - Tessellator t; - auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + ASSERT_EQ(polyline.points.size(), 1u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); +} - ASSERT_EQ(polyline.points.size(), 1u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); - } +// Two points. +{ + Tessellator t; + auto polyline = + PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - // Two points. - { - Tessellator t; - auto polyline = - PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + ASSERT_EQ(polyline.points.size(), 2u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); +} - ASSERT_EQ(polyline.points.size(), 2u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); +// Many points. +{ + Tessellator t; + PathBuilder builder; + for (int i = 0; i < 1000; i++) { + auto coord = i * 1.0f; + builder.AddLine({coord, coord}, {coord + 1, coord + 1}); } + auto polyline = builder.TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - // Many points. - { - Tessellator t; - PathBuilder builder; - for (int i = 0; i < 1000; i++) { - auto coord = i * 1.0f; - builder.AddLine({coord, coord}, {coord + 1, coord + 1}); - } - auto polyline = builder.TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - - ASSERT_EQ(polyline.points.size(), 2000u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); - } + ASSERT_EQ(polyline.points.size(), 2000u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); +} <<<<<<< HEAD ======= } @@ -136,7 +134,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) { ASSERT_EQ(result, Tessellator::Result::kInputError); } >>>>>>> main -} +} // namespace impeller } // namespace testing } // namespace impeller From 60f5780d91ff2a82f3290343782ff6f2397185af Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 18:31:05 +0000 Subject: [PATCH 3/6] Update test_suites.yaml --- .ci.yaml | 3 +- impeller/tessellator/tessellator_unittests.cc | 89 +++++++------ .../backends/skia/text_render_context_skia.cc | 117 ++++++++++-------- sky/tools/macos.gni | 41 ------ sky/tools/strip_bitcode.py | 44 ------- testing/fuchsia/test_suites.yaml | 4 +- 6 files changed, 115 insertions(+), 183 deletions(-) delete mode 100644 sky/tools/macos.gni delete mode 100755 sky/tools/strip_bitcode.py diff --git a/.ci.yaml b/.ci.yaml index 5ae3973d3e3c0..a612973c40e6f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -312,10 +312,11 @@ targets: - name: Mac mac_host_engine recipe: engine_v2/engine_v2 + bringup: true timeout: 60 properties: config_name: mac_host_engine - environment: Production + environment: Staging - name: Mac Unopt recipe: engine/engine_unopt diff --git a/impeller/tessellator/tessellator_unittests.cc b/impeller/tessellator/tessellator_unittests.cc index 96859cd05699d..24af4306c4fdf 100644 --- a/impeller/tessellator/tessellator_unittests.cc +++ b/impeller/tessellator/tessellator_unittests.cc @@ -10,56 +10,56 @@ namespace impeller { namespace testing { -TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus){// Zero points. - {Tessellator t; -auto polyline = PathBuilder{}.TakePath().CreatePolyline(); -Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - -ASSERT_EQ(polyline.points.size(), 0u); -ASSERT_EQ(result, Tessellator::Result::kInputError); -} // namespace testing +TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) { + // Zero points. + { + Tessellator t; + auto polyline = PathBuilder{}.TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); -// One point. -{ - Tessellator t; - auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + ASSERT_EQ(polyline.points.size(), 0u); + ASSERT_EQ(result, Tessellator::Result::kInputError); + } - ASSERT_EQ(polyline.points.size(), 1u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); -} + // One point. + { + Tessellator t; + auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); -// Two points. -{ - Tessellator t; - auto polyline = - PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + ASSERT_EQ(polyline.points.size(), 1u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); + } - ASSERT_EQ(polyline.points.size(), 2u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); -} + // Two points. + { + Tessellator t; + auto polyline = + PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); -// Many points. -{ - Tessellator t; - PathBuilder builder; - for (int i = 0; i < 1000; i++) { - auto coord = i * 1.0f; - builder.AddLine({coord, coord}, {coord + 1, coord + 1}); + ASSERT_EQ(polyline.points.size(), 2u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); } - auto polyline = builder.TakePath().CreatePolyline(); - Tessellator::Result result = - t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); - ASSERT_EQ(polyline.points.size(), 2000u); - ASSERT_EQ(result, Tessellator::Result::kSuccess); -} -<<<<<<< HEAD -======= + // Many points. + { + Tessellator t; + PathBuilder builder; + for (int i = 0; i < 1000; i++) { + auto coord = i * 1.0f; + builder.AddLine({coord, coord}, {coord + 1, coord + 1}); + } + auto polyline = builder.TakePath().CreatePolyline(); + Tessellator::Result result = + t.Tessellate(FillType::kPositive, polyline, [](Point point) {}); + + ASSERT_EQ(polyline.points.size(), 2000u); + ASSERT_EQ(result, Tessellator::Result::kSuccess); + } } TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) { @@ -133,8 +133,7 @@ TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) { ASSERT_EQ(polyline.points.size(), 2u); ASSERT_EQ(result, Tessellator::Result::kInputError); } ->>>>>>> main -} // namespace impeller +} } // namespace testing } // namespace impeller diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 9002452427e55..8fd0ca08a0fc5 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -4,14 +4,12 @@ #include "impeller/typographer/backends/skia/text_render_context_skia.h" -#include #include #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/base/allocation.h" #include "impeller/renderer/allocator.h" -#include "impeller/renderer/device_buffer.h" #include "impeller/typographer/backends/skia/typeface_skia.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -240,59 +238,32 @@ static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, #undef nearestpt } -static std::shared_ptr CreateAtlasTexture( - const std::shared_ptr& allocator, - const GlyphAtlas& atlas, - const ISize& atlas_size) { +static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, + const ISize& atlas_size) { TRACE_EVENT0("impeller", __FUNCTION__); auto bitmap = std::make_shared(); SkImageInfo image_info; - PixelFormat format; switch (atlas.GetType()) { case GlyphAtlas::Type::kSignedDistanceField: case GlyphAtlas::Type::kAlphaBitmap: - format = PixelFormat::kA8UNormInt; image_info = SkImageInfo::MakeA8(atlas_size.width, atlas_size.height); break; case GlyphAtlas::Type::kColorBitmap: - format = PixelFormat::kR8G8B8A8UNormInt; image_info = SkImageInfo::MakeN32Premul(atlas_size.width, atlas_size.height); break; } - auto row_bytes = - std::max(static_cast(image_info.minRowBytes()), - static_cast(allocator->MinimumBytesPerRow(format))); - - DeviceBufferDescriptor buffer_descriptor; - buffer_descriptor.storage_mode = StorageMode::kHostVisible; - buffer_descriptor.size = image_info.computeByteSize(row_bytes); - - auto buffer = allocator->CreateBuffer(buffer_descriptor); - if (!buffer) { - return nullptr; - } - - auto pixels = reinterpret_cast(buffer->AsBufferView().contents); - if (!pixels) { - FML_LOG(ERROR) << "No pixels"; - return nullptr; - } - - if (!bitmap->installPixels(image_info, pixels, row_bytes)) { - FML_LOG(ERROR) << "No install pixels"; + if (!bitmap->tryAllocPixels(image_info)) { return nullptr; } auto surface = SkSurface::MakeRasterDirect(bitmap->pixmap()); if (!surface) { - FML_LOG(ERROR) << "No surf"; return nullptr; } auto canvas = surface->getCanvas(); if (!canvas) { - FML_LOG(ERROR) << "No canv"; return nullptr; } @@ -323,20 +294,48 @@ static std::shared_ptr CreateAtlasTexture( return true; }); - if (atlas.GetType() == GlyphAtlas::Type::kSignedDistanceField) { - ConvertBitmapToSignedDistanceField( - reinterpret_cast(bitmap->getPixels()), atlas_size.width, - atlas_size.height); + return bitmap; +} + +static std::shared_ptr UploadGlyphTextureAtlas( + const std::shared_ptr& allocator, + std::shared_ptr bitmap, + const ISize& atlas_size, + PixelFormat format) { + TRACE_EVENT0("impeller", __FUNCTION__); + if (!allocator) { + return nullptr; } - { - TRACE_EVENT0("impeller", "Texture Creation/Upload"); - TextureDescriptor texture_descriptor; - texture_descriptor.storage_mode = StorageMode::kHostVisible; - texture_descriptor.format = format; - texture_descriptor.size = atlas_size; - return buffer->AsTexture(*allocator, texture_descriptor, row_bytes); + FML_DCHECK(bitmap != nullptr); + const auto& pixmap = bitmap->pixmap(); + + TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = format; + texture_descriptor.size = atlas_size; + + if (pixmap.rowBytes() * pixmap.height() != + texture_descriptor.GetByteSizeOfBaseMipLevel()) { + return nullptr; } + + auto texture = allocator->CreateTexture(texture_descriptor); + if (!texture || !texture->IsValid()) { + return nullptr; + } + texture->SetLabel("GlyphAtlas"); + + auto mapping = std::make_shared( + reinterpret_cast(bitmap->getAddr(0, 0)), // data + texture_descriptor.GetByteSizeOfBaseMipLevel(), // size + [bitmap](auto, auto) mutable { bitmap.reset(); } // proc + ); + + if (!texture->SetContents(mapping)) { + return nullptr; + } + return texture; } std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( @@ -387,23 +386,41 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 5: Create a texture and draw font-glyph pairs in the correct spot in - // the atlas. + // Step 5: Draw font-glyph pairs in the correct spot in the atlas. // --------------------------------------------------------------------------- + auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); + if (!bitmap) { + return nullptr; + } - auto texture = CreateAtlasTexture(GetContext()->GetResourceAllocator(), - *glyph_atlas, atlas_size); - + // --------------------------------------------------------------------------- + // Step 6: Upload the atlas as a texture. + // --------------------------------------------------------------------------- + PixelFormat format; + switch (type) { + case GlyphAtlas::Type::kSignedDistanceField: + ConvertBitmapToSignedDistanceField( + reinterpret_cast(bitmap->getPixels()), atlas_size.width, + atlas_size.height); + case GlyphAtlas::Type::kAlphaBitmap: + format = PixelFormat::kA8UNormInt; + break; + case GlyphAtlas::Type::kColorBitmap: + format = PixelFormat::kR8G8B8A8UNormInt; + break; + } + auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(), + bitmap, atlas_size, format); if (!texture) { return nullptr; } // --------------------------------------------------------------------------- - // Step 6: Record the texture in the glyph atlas. + // Step 7: Record the texture in the glyph atlas. // --------------------------------------------------------------------------- glyph_atlas->SetTexture(std::move(texture)); return glyph_atlas; } -} // namespace impeller +} // namespace impeller \ No newline at end of file diff --git a/sky/tools/macos.gni b/sky/tools/macos.gni deleted file mode 100644 index f321dda68aba2..0000000000000 --- a/sky/tools/macos.gni +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//flutter/common/config.gni") - -# Copies an input macOS binary to the specified output path. Bitcode segments, -# if any, are stripped. -# -# Example: -# -# strip_bitcode( -# input = "$root_build_dir/gen_snapshot" -# output = "$root_build_dir/gen_snapshot_arm64" -# deps = [ ":gen_snapshot" ] -# ) -# -# TODO(cbracken): https://github.com/flutter/flutter/issues/107884 -# When we stop building with bitcode enabled, this template and the -# strip_bitcode.py script can be deleted and users can call copy() instead. -template("strip_bitcode") { - assert(defined(invoker.input), "The input to strip_bitcode must be defined") - assert(defined(invoker.output), "The output to strip_bitcode most be defined") - action(target_name) { - forward_variables_from(invoker, - [ - "deps", - "metadata", - "visibility", - ]) - script = "//flutter/sky/tools/strip_bitcode.py" - args = [ - "--input", - rebase_path(invoker.input), - "--output", - rebase_path(invoker.output), - ] - inputs = [ invoker.input ] - outputs = [ invoker.output ] - } -} diff --git a/sky/tools/strip_bitcode.py b/sky/tools/strip_bitcode.py deleted file mode 100755 index c5786ad5610fe..0000000000000 --- a/sky/tools/strip_bitcode.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import argparse -import os -import subprocess -import sys - - -def main(): - parser = argparse.ArgumentParser( - description='Copies an input macOS binary to the specified output path. ' - 'Bitcode segments, if any, are stripped.' - ) - parser.add_argument( - '--input', - type=str, - required=True, - help='path of input binary to be read' - ) - parser.add_argument( - '--output', - type=str, - required=True, - help='path of output binary to be written' - ) - args = parser.parse_args() - - # Verify input binary exists. - if not os.path.isfile(args.input): - print('Cannot find input binary at %s' % args.input) - sys.exit(1) - - # Copy input path to output path. Strip bitcode segments, if any. - subprocess.check_call([ - 'xcrun', 'bitcode_strip', '-r', args.input, '-o', args.output - ]) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/testing/fuchsia/test_suites.yaml b/testing/fuchsia/test_suites.yaml index f3c985ec78d4b..346772c341404 100644 --- a/testing/fuchsia/test_suites.yaml +++ b/testing/fuchsia/test_suites.yaml @@ -41,10 +41,10 @@ packages: - oot_dart_jit_runner-0.far - dart-jit-runner-integration-test-0.far - - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_jit_echo_server/dart_jit_echo_server/dart_jit_echo_server.far + - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_echo_server/dart_jit_echo_server/dart_jit_echo_server.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart-aot-runner-integration-test#meta/dart-aot-runner-integration-test.cm run_with_dart_aot: 'true' packages: - oot_dart_aot_runner-0.far - dart-aot-runner-integration-test-0.far - - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart_aot_echo_server/dart_aot_echo_server/dart_aot_echo_server.far + - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart_echo_server/dart_aot_echo_server/dart_aot_echo_server.far From a33a20bca14c28cbfa96c01ba4011b3962de5d05 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 18:31:55 +0000 Subject: [PATCH 4/6] Add new line --- impeller/typographer/backends/skia/text_render_context_skia.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index 8fd0ca08a0fc5..96ef3f6851839 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -423,4 +423,4 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( return glyph_atlas; } -} // namespace impeller \ No newline at end of file +} // namespace impeller From 343603d238d10b793b4ad9040f8f7e49d03c8e78 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 18:51:37 +0000 Subject: [PATCH 5/6] Correct directory for test_suites.yaml --- testing/fuchsia/test_suites.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/fuchsia/test_suites.yaml b/testing/fuchsia/test_suites.yaml index 346772c341404..3ecc4df2306f3 100644 --- a/testing/fuchsia/test_suites.yaml +++ b/testing/fuchsia/test_suites.yaml @@ -41,10 +41,10 @@ packages: - oot_dart_jit_runner-0.far - dart-jit-runner-integration-test-0.far - - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_jit_runner/dart_echo_server/dart_jit_echo_server/dart_jit_echo_server.far + - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/dart_jit_echo_server/dart_jit_echo_server.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart-aot-runner-integration-test#meta/dart-aot-runner-integration-test.cm run_with_dart_aot: 'true' packages: - oot_dart_aot_runner-0.far - dart-aot-runner-integration-test-0.far - - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_aot_runner/dart_echo_server/dart_aot_echo_server/dart_aot_echo_server.far + - gen/flutter/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/dart_aot_echo_server/dart_aot_echo_server.far From 0edb9ebe5279693bcaf0264fa2b03608d47ef241 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Oct 2022 15:00:38 -0700 Subject: [PATCH 6/6] Update README.md --- .../tests/startup_integration_test/dart_echo_server/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md index 4d2e098a69ec7..7e91d785abf37 100644 --- a/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md +++ b/shell/platform/fuchsia/dart_runner/tests/startup_integration_test/dart_echo_server/README.md @@ -2,6 +2,6 @@ Contains the Echo servers for the integration tests. There are currently two outputs: - `dart-aot-echo-server` -- `dart-jit-ehco-server` +- `dart-jit-echo-server` -The outputs run with their respective Dart runners and are consumed by their respective integration test. \ No newline at end of file +The outputs run with their respective Dart runners and are consumed by their respective integration test.