diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index d0f70fdd13cea..0000000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,23 +0,0 @@ -# See Dependabot documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - groups: - all-github-actions: - patterns: [ "*" ] - reviewers: - - "christopherfujino" - - "jmagman" - labels: - - "team-infra" - - "autosubmit" - # Updating patch versions for "github-actions" is too chatty. - # See https://github.com/flutter/flutter/issues/158350. - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-patch"] diff --git a/.github/labeler.yml b/.github/labeler.yml deleted file mode 100644 index 72b7c66fd1ae1..0000000000000 --- a/.github/labeler.yml +++ /dev/null @@ -1,261 +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. - -# See https://github.com/actions/labeler/blob/main/README.md for docs. -# Use git ls-files '' to see the list of matching files. - -'a: accessibility': - - changed-files: - - any-glob-to-any-file: - - '**/accessibility/*' - - '**/*accessibility*' - - '**/semantics/*' - - '**/*semantics*' - -'a: animation': - - changed-files: - - any-glob-to-any-file: - - '**/animation/*' - - '**/*animation*' - -'a: desktop': - - changed-files: - - any-glob-to-any-file: - - '**/linux/**/*' - - '**/macos/**/*' - - '**/windows/**/*' - - engine/src/flutter/shell/platform/darwin/common/**/* - -'a: internationalization': - - changed-files: - - any-glob-to-any-file: - - packages/flutter_localizations/**/* - -'a: tests': - - changed-files: - - any-glob-to-any-file: - - packages/flutter_driver/**/* - - packages/flutter_goldens/**/* - - packages/flutter_test/**/* - - packages/integration_test/**/* - -'a: text input': - - changed-files: - - all-globs-to-any-file: - - '**/*text*' - - '!**/*context*' - - '!**/*texture*' - -'d: api docs': - - changed-files: - - any-glob-to-any-file: - - examples/api/**/* - -'d: docs/': - - changed-files: - - any-glob-to-any-file: - - docs/**/* - -'d: examples': - - changed-files: - - any-glob-to-any-file: - - examples/**/* - -'e: embedder': - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/embedder - -'e: impeller': - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/impeller/**/* - -engine: - - changed-files: - - any-glob-to-any-file: - - DEPS - - engine/**/* - - docs/engine/**/* - -'f: cupertino': - - changed-files: - - any-glob-to-any-file: - - '**/cupertino/*' - - '**/*cupertino*' - - docs/libraries/cupertino/**/* - -'f: focus': - - changed-files: - - any-glob-to-any-file: - - '**/focus/*' - - '**/*focus*' - -'f: gestures': - - changed-files: - - any-glob-to-any-file: - - '**/gestures/*' - - '**/*gestures*' - -'f: material design': - - changed-files: - - any-glob-to-any-file: - - '**/material/*' - - '**/*material*' - - docs/libraries/material/**/* - -'f: routes': - - changed-files: - - any-glob-to-any-file: - - '**/navigator/*' - - '**/*navigator*' - - '**/route/*' - - '**/*route*' - -'f: scrolling': - - changed-files: - - any-glob-to-any-file: - - '**/*scroll*' - - '**/scroll/*' - - '**/*sliver*' - - '**/sliver/*' - - '**/*viewport*' - - '**/viewport/*' - -framework: - - changed-files: - - any-glob-to-any-file: - - packages/flutter/**/* - - packages/flutter_driver/**/* - - packages/flutter_goldens/**/* - - packages/flutter_localizations/**/* - - packages/flutter_test/**/* - - packages/integration_test/**/* - - examples/api/**/* - - docs/about/**/* - - docs/contributing/**/* - - docs/libraries/**/* - -'f: integration_test': - - changed-files: - - any-glob-to-any-file: - - packages/integration_test/**/* - -package: - - changed-files: - - any-glob-to-any-file: - - docs/ecosystem/**/* - -platform-android: - - changed-files: - - any-glob-to-any-file: - - docs/platform/android/**/* - - engine/src/flutter/shell/platform/android/**/* - - packages/flutter_tools/*android* - - packages/flutter_tools/gradle/**/* - -platform-ios: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/darwin/common/**/* - - engine/src/flutter/shell/platform/darwin/ios/**/* - - packages/flutter_tools/lib/src/ios/**/* - -platform-fuchsia: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/fuchsia/**/* - -platform-linux: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/linux/**/* - -platform-macos: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/src/flutter/shell/platform/darwin/common/**/* - - engine/src/flutter/shell/platform/darwin/macos/**/* - -platform-web: - - changed-files: - - any-glob-to-any-file: - - '**/web_sdk/**/*' - - engine/src/flutter/lib/web_ui/**/* - - packages/flutter_web_plugins - -platform-windows: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/windows/**/* - -'customer: gallery': - - changed-files: - - any-glob-to-any-file: - - examples/flutter_gallery/**/* - -'c: tech-debt': - - changed-files: - - any-glob-to-any-file: - - '**/fix_data.yaml' - - '**/*.expect' - - '**/*test_fixes*' -'c: contributor-productivity': - - changed-files: - - any-glob-to-any-file: - - docs/contributing/**/* - -# Keep this synced with CODEOWNERS. -team-android: - - changed-files: - - any-glob-to-any-file: - - docs/platform/android/**/* - - engine/src/flutter/shell/platform/android/**/* - - packages/flutter_tools/**/*android* - - packages/flutter_tools/**/*gradle* - -team-ecosystem: - - changed-files: - - any-glob-to-any-file: - - docs/ecosystem/**/* - -team-engine: - - changed-files: - - any-glob-to-any-file: - - docs/engine/**/* - -team-infra: - - changed-files: - - any-glob-to-any-file: - - docs/infra/**/* - - docs/releases/**/* - -# Keep this synced with CODEOWNERS. -team-ios: - - changed-files: - - any-glob-to-any-file: - - engine/src/flutter/shell/platform/darwin/common/**/* - - engine/src/flutter/shell/platform/darwin/ios/framework/**/* - - packages/flutter_tools/**/ios/* - - packages/flutter_tools/**/macos/* - - packages/flutter_tools/**/*xcode* - - packages/flutter_tools/**/*ios* - - packages/flutter_tools/**/*macos* - -team-tool: - - changed-files: - - any-glob-to-any-file: - - docs/tool/**/* - -team-web: - - changed-files: - - any-glob-to-any-file: - - docs/platforms/web/**/* - -tool: - - changed-files: - - any-glob-to-any-file: - - packages/flutter_tools/**/* - - packages/fuchsia_remote_debug_protocol/**/* - - docs/tool/**/* diff --git a/.github/release.yml b/.github/release.yml deleted file mode 100644 index 5c6decc52930e..0000000000000 --- a/.github/release.yml +++ /dev/null @@ -1,68 +0,0 @@ -changelog: - exclude: - authors: - - engine-flutter-autoroll - - fluttergithubbot - labels: - - passed first triage - - passed secondary triage - - "team: flakes" - - revert - categories: - - title: Framework - labels: - - framework - - "a: text input" - - "f: scrolling" - - "f: routes" - - "f: selection" - - "f: gestures" - exclude: - labels: - - "f: material design" - - title: Material - labels: - - "f: material design" - # Mobile - - title: iOS - labels: - - platform-ios - - "f: cupertino" - - title: Android - labels: - - platform-android - # Desktop - - title: macOS - labels: - - platform-mac - - title: Windows - labels: - - platform-windows - - title: Linux - labels: - - platform-linux - # Web - - title: Web - labels: - - platform-web - - "browser: chrome-desktop" - - "browser: edge" - - "browser: firefox" - - "browser: safari-macos" - # Misc - - title: Tooling - labels: - - tool - - title: DevTools - labels: - - "d: devtools" - - "d: intellij" - - "d: tools_metadata" - - "f: inspector" - - title: Documentation - labels: - - "d: examples" - - "d: api docs" - - title: Other Changes - labels: - - '*' diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml new file mode 100644 index 0000000000000..d15fb0f88456b --- /dev/null +++ b/.github/workflows/build-docker.yml @@ -0,0 +1,21 @@ +name: Build Docker + +on: [workflow_dispatch] + +jobs: + builder: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/build-push-action@v5 + with: + context: engine/src/flutter/ci/tizen + file: engine/src/flutter/ci/tizen/Dockerfile + push: true + tags: ghcr.io/${{ github.repository_owner }}/build-engine:latest diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000..67a4a1cfcec32 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,355 @@ +name: Build + +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + container: + image: ghcr.io/flutter-tizen/build-engine:latest + credentials: + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + strategy: + matrix: + arch: [arm, arm64, x86, x64] + mode: [debug, release, profile] + include: + - arch: arm + triple: arm-linux-gnueabi + - arch: arm64 + triple: aarch64-linux-gnu + - arch: x86 + triple: i686-linux-gnu + - arch: x64 + triple: x86_64-linux-gnu + exclude: + - arch: x86 + mode: release + - arch: x86 + mode: profile + + steps: + - uses: actions/checkout@v4 + with: + path: flutter + fetch-depth: 1 + + - uses: actions/cache@v4 + with: + path: /tizen_tools/sysroot + key: sysroot + + - name: Install depot_tools + run: | + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + echo "$PWD/depot_tools" >> $GITHUB_PATH + export PATH="$PWD/depot_tools:$PATH" + # Install ninja + apt install ninja-build + + - name: Run gclient sync + run: | + cd flutter + gclient config --unmanaged https://github.com/flutter-tizen/flutter + sed -i "s/'flutter'/'.'/g" ./.gclient + gclient setdep --var=download_dart_sdk=False --var=download_android_deps=False --var=download_fuchsia_deps=False --deps-file=DEPS + gclient sync -v --no-history --shallow + + - name: Generate sysroot + run: flutter/engine/src/flutter/ci/tizen/generate_sysroot.py --out /tizen_tools/sysroot + + - name: Build + if: ${{ matrix.arch != 'x64' }} + run: | + cd flutter + # Ignore unsupported linker option. + sed -i "/-Wl,--undefined-version/d" engine/src/build/config/compiler/BUILD.gn + sed -i "s/Wno-nontrivial-memcall/Wno-nontrivial-memaccess/g" engine/src/build/config/compiler/BUILD.gn + + engine/src/flutter/tools/gn \ + --target-os linux \ + --linux-cpu ${{ matrix.arch }} \ + --no-goma \ + --no-lto \ + --target-toolchain /tizen_tools/toolchains \ + --target-sysroot /tizen_tools/sysroot/${{ matrix.arch }} \ + --target-triple ${{ matrix.triple }} \ + --runtime-mode ${{ matrix.mode }} \ + --enable-fontconfig \ + --disable-desktop-embeddings \ + --target-dir build + cd engine/src + ninja -C out/build flutter_engine_library + cp -f flutter/third_party/icu/flutter/icudtl.dat out/build + + - name: Build(x64) + if: ${{ matrix.arch == 'x64' }} + run: | + cd flutter + + engine/src/flutter/tools/gn \ + --target-os linux \ + --linux-cpu ${{ matrix.arch }} \ + --no-goma \ + --target-triple ${{ matrix.triple }} \ + --runtime-mode ${{ matrix.mode }} \ + --enable-fontconfig \ + --disable-desktop-embeddings \ + --target-dir build + + cd engine/src + ninja -C out/build flutter_engine_library + cp -f flutter/third_party/icu/flutter/icudtl.dat out/build + + - name: Build gen_snapshot + if: ${{ matrix.mode != 'debug' && matrix.arch != 'x64'}} + run: | + cd flutter + ninja -C engine/src/out/build clang_x64/gen_snapshot + + - name: Build gen_snapshot(x64) + if: ${{ matrix.mode != 'debug' && matrix.arch == 'x64'}} + run: | + cd flutter + ninja -C engine/src/out/build gen_snapshot + + - uses: actions/upload-artifact@v4 + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }} + path: | + flutter/engine/src/out/build/libflutter_engine.so + flutter/engine/src/out/build/icudtl.dat + if-no-files-found: error + + - uses: actions/upload-artifact@v4 + if: ${{ github.event_name == 'push' && matrix.arch != 'x64' }} + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_symbols + path: flutter/engine/src/out/build/so.unstripped/libflutter_engine.so + if-no-files-found: error + + - uses: actions/upload-artifact@v4 + if: ${{ matrix.mode != 'debug' && matrix.arch != 'x64'}} + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_linux-x64 + path: flutter/engine/src/out/build/clang_x64/gen_snapshot + if-no-files-found: error + + - uses: actions/upload-artifact@v4 + if: ${{ matrix.mode != 'debug' && matrix.arch == 'x64'}} + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_linux-x64 + path: flutter/engine/src/out/build/gen_snapshot + if-no-files-found: error + + windows-build: + runs-on: windows-2022 + + strategy: + matrix: + arch: [arm, arm64] + mode: [release, profile] + + steps: + - name: Run git checkout + run: | + mkdir C:\workspace\flutter + cd C:\workspace\flutter + git config --global core.autocrlf false + git config --global core.filemode false + git config --global core.fscache true + git config --global core.preloadindex true + git config --global depot-tools.allowGlobalGitConfig true + git init --quiet + git remote add origin https://github.com/${{ github.repository }} + git fetch --depth 1 origin ${{ github.sha }} + git checkout FETCH_HEAD + + - name: Environment setup + run: | + Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Force + echo "DEPOT_TOOLS_WIN_TOOLCHAIN=0" >> $Env:GITHUB_ENV + echo "GYP_MSVS_OVERRIDE_PATH=C:\Program Files\Microsoft Visual Studio\2022\Enterprise" >> $Env:GITHUB_ENV + echo "WINDOWSSDKDIR=C:\Program Files (x86)\Windows Kits\10" >> $Env:GITHUB_ENV + + - name: Install depot_tools + run: | + Invoke-WebRequest -Uri https://storage.googleapis.com/chrome-infra/depot_tools.zip -OutFile depot_tools.zip + 7z x -y -o"C:\workspace\depot_tools" .\depot_tools.zip + echo "C:\workspace\depot_tools" >> $Env:GITHUB_PATH + + - name: Run gclient sync + working-directory: C:\workspace\flutter + shell: powershell + run: | + gclient config --unmanaged https://github.com/flutter-tizen/flutter + (Get-Content ".gclient") | ForEach-Object { $_ -replace "'flutter'","'.'" } | Set-Content ".gclient" + # TODO(jsuya) : pipes deprecated in python 3.13. (https://dart-review.googlesource.com/c/sdk/+/307620) + (Get-Content "engine/src/build/vs_toolchain.py") | ForEach-Object { $_ -replace 'import pipes','' } | Set-Content "engine/src/build/vs_toolchain.py" + + # TODO(jsuya) : Temporary fix to Microsoft STL compiler compatibility checks(https://github.com/flutter-tizen/flutter-tizen/pull/635#issuecomment-2990206946) + (Get-Content "engine/src/build/config/compiler/BUILD.gn") | ForEach-Object { $_; if ($_.Trim() -eq '"__STD_C",') { ' "_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH",' } } | Set-Content "engine/src/build/config/compiler/BUILD.gn" + + gclient setdep --var=download_dart_sdk=False --var=download_android_deps=False --var=download_fuchsia_deps=False --deps-file=DEPS + gclient sync -v --no-history --shallow + + - name: Build + working-directory: C:\workspace\flutter\engine\src + run: | + python3 .\flutter\tools\gn ` + --linux ` + --linux-cpu=${{ matrix.arch }} ` + --runtime-mode=${{ matrix.mode }} ` + --no-goma ` + --target-dir build + ninja -C .\out\build gen_snapshot + + - uses: actions/upload-artifact@v4 + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_windows-x64 + path: C:\workspace\flutter\engine\src\out\build\gen_snapshot.exe + if-no-files-found: error + + macos-build: + runs-on: macos-latest + + strategy: + matrix: + arch: [arm, arm64] + mode: [release, profile] + + steps: + - uses: actions/checkout@v4 + with: + path: flutter + fetch-depth: 1 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install depot_tools + run: | + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + echo "$PWD/depot_tools" >> $GITHUB_PATH + + - name: Run gclient sync + run: | + cd flutter + gclient config --unmanaged https://github.com/flutter-tizen/flutter + sed -i '' "s/'flutter'/'.'/g" .gclient + gclient setdep --var=download_dart_sdk=False --var=download_android_deps=False --var=download_fuchsia_deps=False --deps-file=DEPS + gclient sync -v --no-history --shallow + + - name: Build + run: | + cd flutter + # Change host_toolchain to mac/clang_arm64. + sed -i "" "s|//build/toolchain/linux:clang_$host_cpu|//build/toolchain/mac:clang_$host_cpu|g" engine/src/build/config/BUILDCONFIG.gn + + # Pass dummy values to prevent using the default (Linux) toolchain. + engine/src/flutter/tools/gn \ + --linux \ + --linux-cpu=${{ matrix.arch }} \ + --no-goma \ + --target-toolchain _ \ + --target-sysroot _ \ + --target-triple _ \ + --runtime-mode=${{ matrix.mode }} \ + --disable-desktop-embeddings \ + --target-dir build + cd engine/src + ninja -C out/build clang_arm64/gen_snapshot + + - uses: actions/upload-artifact@v4 + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_darwin-arm64 + path: flutter/engine/src/out/build/clang_arm64/gen_snapshot + if-no-files-found: error + + macos-intel-build: + runs-on: macos-15-intel + + strategy: + matrix: + arch: [arm, arm64] + mode: [release, profile] + + steps: + - uses: actions/checkout@v4 + with: + path: flutter + fetch-depth: 1 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install depot_tools + run: | + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + echo "$PWD/depot_tools" >> $GITHUB_PATH + + - name: Run gclient sync + run: | + cd flutter + gclient config --unmanaged https://github.com/flutter-tizen/flutter + sed -i '' "s/'flutter'/'.'/g" .gclient + gclient setdep --var=download_dart_sdk=False --var=download_android_deps=False --var=download_fuchsia_deps=False --deps-file=DEPS + gclient sync -v --no-history --shallow + + - name: Build + run: | + cd flutter + # Change host_toolchain to mac/clang_x64. + sed -i "" "s|//build/toolchain/linux:clang_$host_cpu|//build/toolchain/mac:clang_$host_cpu|g" engine/src/build/config/BUILDCONFIG.gn + + # Pass dummy values to prevent using the default (Linux) toolchain. + engine/src/flutter/tools/gn \ + --linux \ + --linux-cpu=${{ matrix.arch }} \ + --no-goma \ + --target-toolchain _ \ + --target-sysroot _ \ + --target-triple _ \ + --runtime-mode=${{ matrix.mode }} \ + --disable-desktop-embeddings \ + --target-dir build + cd engine/src + ninja -C out/build clang_x64/gen_snapshot + + - uses: actions/upload-artifact@v4 + with: + name: tizen-${{ matrix.arch }}-${{ matrix.mode }}_darwin-x64 + path: flutter/engine/src/out/build/clang_x64/gen_snapshot + if-no-files-found: error + + release: + needs: [build] + if: ${{ github.event_name == 'push' }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + + - name: Create archives + run: | + for name in tizen-*; do + 7z a $name.zip ./$name/* + done + + - name: Set variables + run: | + echo "SHORT_SHA=$(git rev-parse --short $GITHUB_SHA)" >> $GITHUB_ENV + echo "VERSION=$(echo "${{ github.ref_name }}" | cut -d'-' -f2)" >> $GITHUB_ENV + + - uses: softprops/action-gh-release@v2 + with: + name: ${{ env.VERSION }} (${{ env.SHORT_SHA }}) + tag_name: ${{ env.SHORT_SHA }} + target_commitish: ${{ github.sha }} + files: tizen-*.zip + body: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml deleted file mode 100644 index 193049ebb9400..0000000000000 --- a/.github/workflows/labeler.yml +++ /dev/null @@ -1,22 +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. - -name: "Pull Request Labeler" -on: -- pull_request_target - -# Declare default permissions as read only. -permissions: read-all - -jobs: - triage: - if: ${{ github.repository == 'flutter/flutter' }} - permissions: - pull-requests: write - runs-on: ubuntu-latest - steps: - # Source available at https://github.com/actions/labeler/blob/main/README.md - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b - with: - sync-labels: true diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml deleted file mode 100644 index a568c78265469..0000000000000 --- a/.github/workflows/mirror.yml +++ /dev/null @@ -1,28 +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. - -# Mirror master to main branches in the flutter repository. -on: - push: - branches: - - 'master' - -# Declare default permissions as read only. -permissions: read-all - -jobs: - mirror_job: - permissions: - pull-requests: write - runs-on: ubuntu-latest - if: ${{ github.repository == 'flutter/flutter' }} - name: Mirror master branch to main branch - steps: - - name: Mirror action step - id: mirror - uses: google/mirror-branch-action@30c52ee21f5d3bd7fb28b95501c11aae7f17eebb - with: - github-token: ${{ secrets.FLUTTERMIRRORINGBOT_TOKEN }} - source: 'master' - dest: 'main' diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml deleted file mode 100644 index 94d4d8fc988ce..0000000000000 --- a/.github/workflows/no-response.yaml +++ /dev/null @@ -1,44 +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. - -name: No Response - -# Both `issue_comment` and `scheduled` event types are required for this Action -# to work properly. -on: - issue_comment: - types: [created] - schedule: - # Schedule for five minutes after the hour, every hour - - cron: '5 * * * *' - -# By specifying the access of one of the scopes, all of those that are not -# specified are set to 'none'. -permissions: - issues: write - -jobs: - noResponse: - runs-on: ubuntu-latest - if: ${{ github.repository == 'flutter/flutter' }} - steps: - - uses: godofredoc/no-response@0ce2dc0e63e1c7d2b87752ceed091f6d32c9df09 - with: - token: ${{ github.token }} - # Comment to post when closing an Issue for lack of response. Set to `false` to disable - closeComment: > - Without additional information, we are unfortunately not sure how to - resolve this issue. We are therefore reluctantly going to close this - bug for now. - - If you find this problem please file a new issue with the same description, - what happens, logs and the output of 'flutter doctor -v'. All system setups - can be slightly different so it's always better to open new issues and reference - the related ones. - - Thanks for your contribution. - # Number of days of inactivity before an issue is closed for lack of response. - daysUntilClose: 21 - # Label requiring a response. - responseRequiredLabel: "waiting for customer response" diff --git a/DEPS b/DEPS index 0139ff7ebda07..a4fe246ccff4c 100644 --- a/DEPS +++ b/DEPS @@ -127,7 +127,7 @@ vars = { "checkout_llvm": False, # Setup Git hooks by default. - 'setup_githooks': True, + 'setup_githooks': False, # When this is true, the Flutter Engine's configuration files and scripts for # RBE will be downloaded from CIPD. This option is only usable by Googlers. diff --git a/engine/src/build/toolchain/custom/BUILD.gn b/engine/src/build/toolchain/custom/BUILD.gn index 3da5f930269b5..12ccc7c56b6f2 100644 --- a/engine/src/build/toolchain/custom/BUILD.gn +++ b/engine/src/build/toolchain/custom/BUILD.gn @@ -20,6 +20,9 @@ toolchain("custom") { target_triple_flags = "--target=${custom_target_triple}" sysroot_flags = "--sysroot ${custom_sysroot}" + syscall_compat_header = + rebase_path("//build/toolchain/custom/tizen_syscall_compat.h", root_build_dir) + syscall_compat_flags = "-include ${syscall_compat_header}" custom_lib_flags = "-L${custom_toolchain}/lib" @@ -29,7 +32,7 @@ toolchain("custom") { tool("cc") { depfile = "{{output}}.d" - command = "$cc -MD -MF $depfile $target_triple_flags $sysroot_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = "$cc -MD -MF $depfile $target_triple_flags $sysroot_flags $syscall_compat_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CC {{output}}" outputs = @@ -38,7 +41,7 @@ toolchain("custom") { tool("cxx") { depfile = "{{output}}.d" - command = "$cxx -MD -MF $depfile $target_triple_flags $sysroot_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + command = "$cxx -MD -MF $depfile $target_triple_flags $sysroot_flags $syscall_compat_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CXX {{output}}" outputs = @@ -47,7 +50,7 @@ toolchain("custom") { tool("asm") { depfile = "{{output}}.d" - command = "$cc -MD -MF $depfile $target_triple_flags $sysroot_flags {{defines}} {{include_dirs}} {{asmflags}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = "$cc -MD -MF $depfile $target_triple_flags $sysroot_flags $syscall_compat_flags {{defines}} {{include_dirs}} {{asmflags}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "ASM {{output}}" outputs = diff --git a/engine/src/build/toolchain/custom/tizen_syscall_compat.h b/engine/src/build/toolchain/custom/tizen_syscall_compat.h new file mode 100644 index 0000000000000..f3658b2ba3c2e --- /dev/null +++ b/engine/src/build/toolchain/custom/tizen_syscall_compat.h @@ -0,0 +1,32 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BUILD_TOOLCHAIN_CUSTOM_TIZEN_SYSCALL_COMPAT_H_ +#define BUILD_TOOLCHAIN_CUSTOM_TIZEN_SYSCALL_COMPAT_H_ + +// Some Tizen cross-compilation sysroots do not expose __NR_getrandom even +// though the target Linux ABI supports the syscall. Dart's crypto_linux.cc +// references the syscall number directly, so provide the missing arch-specific +// values for custom Linux toolchains without modifying third_party sources. +#if defined(__linux__) + +#if defined(__i386__) && !defined(__NR_getrandom) +#define __NR_getrandom 355 +#endif + +#if defined(__x86_64__) && !defined(__NR_getrandom) +#define __NR_getrandom 318 +#endif + +#if defined(__arm__) && !defined(__NR_getrandom) +#define __NR_getrandom 384 +#endif + +#if defined(__aarch64__) && !defined(__NR_getrandom) +#define __NR_getrandom 278 +#endif + +#endif // defined(__linux__) + +#endif // BUILD_TOOLCHAIN_CUSTOM_TIZEN_SYSCALL_COMPAT_H_ diff --git a/engine/src/build_overrides/vulkan_headers.gni b/engine/src/build_overrides/vulkan_headers.gni index 8ef7d23936589..8a4144db207b6 100644 --- a/engine/src/build_overrides/vulkan_headers.gni +++ b/engine/src/build_overrides/vulkan_headers.gni @@ -6,6 +6,6 @@ # set anything. if (is_linux) { - vulkan_use_x11 = !is_minimal_linux + vulkan_use_x11 = false vulkan_use_wayland = true } diff --git a/engine/src/flutter/ci/tizen/.gitignore b/engine/src/flutter/ci/tizen/.gitignore new file mode 100644 index 0000000000000..c23e7e850155f --- /dev/null +++ b/engine/src/flutter/ci/tizen/.gitignore @@ -0,0 +1,3 @@ +/llvm-project*/ +/toolchains*/ +/sysroot/ diff --git a/engine/src/flutter/ci/tizen/Dockerfile b/engine/src/flutter/ci/tizen/Dockerfile new file mode 100644 index 0000000000000..f5d0f1fc5520f --- /dev/null +++ b/engine/src/flutter/ci/tizen/Dockerfile @@ -0,0 +1,32 @@ +############################### +### Stage for building LLVM ### +############################### + +FROM ubuntu:22.04 AS llvm + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y git zip build-essential cmake ninja-build clang-11 && \ + apt-get clean + +COPY build_llvm.sh . + +RUN /build_llvm.sh + + +############################## +### Create a release image ### +############################## + +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y binutils-arm-linux-gnueabi binutils-aarch64-linux-gnu binutils-i686-linux-gnu && \ + apt-get install -y git curl pkg-config ca-certificates python3 python3-pip rpm2cpio cpio && \ + apt-get clean + +# Copy build artifacts from the previous stage. +COPY --from=llvm /toolchains/ /tizen_tools/toolchains/ diff --git a/engine/src/flutter/ci/tizen/arm.patch b/engine/src/flutter/ci/tizen/arm.patch new file mode 100644 index 0000000000000..1dabb3f2803d4 --- /dev/null +++ b/engine/src/flutter/ci/tizen/arm.patch @@ -0,0 +1,15 @@ +diff --git a/usr/include/asm-arm/hwcap.h b/usr/include/asm-arm/hwcap.h +index da85060..adaf619 100644 +--- a/usr/include/asm-arm/hwcap.h ++++ b/usr/include/asm-arm/hwcap.h +@@ -26,5 +26,10 @@ + #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ + #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) + ++#define HWCAP2_AES (1 << 0) ++#define HWCAP2_PMULL (1 << 1) ++#define HWCAP2_SHA1 (1 << 2) ++#define HWCAP2_SHA2 (1 << 3) ++#define HWCAP2_CRC32 (1 << 4) + + #endif /* __ASMARM_HWCAP_H */ diff --git a/engine/src/flutter/ci/tizen/build_llvm.sh b/engine/src/flutter/ci/tizen/build_llvm.sh new file mode 100755 index 0000000000000..de27efb73a9b6 --- /dev/null +++ b/engine/src/flutter/ci/tizen/build_llvm.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e + +SCRIPT_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +OUTPUT_DIR="$SCRIPT_DIR/toolchains" +cd "$SCRIPT_DIR" + +# Check out the LLVM project source code. +if [ -d llvm-project ]; then + echo "The directory already exists. Skipping download." + cd llvm-project +else + mkdir llvm-project + cd llvm-project + git init + git remote add origin https://github.com/llvm/llvm-project.git + git fetch --depth=1 origin llvmorg-18.1.8 + git checkout FETCH_HEAD +fi + +# Run the ninja build. +mkdir -p build && cd build +cmake -G Ninja \ + -DCLANG_VENDOR="Tizen" \ + -DLLVM_ENABLE_PROJECTS="clang" \ + -DLLVM_TARGETS_TO_BUILD="X86;ARM;AArch64" \ + -DCMAKE_C_COMPILER=clang-11 \ + -DCMAKE_CXX_FLAGS="-mssse3" \ + -DCMAKE_CXX_COMPILER=clang++-11 \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$OUTPUT_DIR" \ + ../llvm +ninja install -j$(nproc) + +# Create symbolic links to binutils. +# See build/toolchain/custom/BUILD.gn for more information. +cd "$OUTPUT_DIR/bin" +for name in ar readelf nm strip; do + ln -sf llvm-$name arm-linux-gnueabi-$name + ln -sf llvm-$name aarch64-linux-gnu-$name + ln -sf llvm-$name i686-linux-gnu-$name + ln -sf llvm-$name x86_64-linux-gnu-$name +done diff --git a/engine/src/flutter/ci/tizen/generate_sysroot.py b/engine/src/flutter/ci/tizen/generate_sysroot.py new file mode 100755 index 0000000000000..210f7e9ecf9e7 --- /dev/null +++ b/engine/src/flutter/ci/tizen/generate_sysroot.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# Copyright 2022 Samsung Electronics Co., Ltd. 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 re +import shutil +import subprocess +import sys +import urllib.parse +import urllib.request +from pathlib import Path + +base_packages = [ + 'gcc', + 'glibc', + 'glibc-devel', + 'libgcc', + 'libstdc++', + 'linux-glibc-devel', + 'zlib-devel', +] + +unified_packages = [ + 'fontconfig', + 'fontconfig-devel', + 'freetype2-devel', + 'libpng-devel', +] + + +def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False): + if arch == 'arm': + tizen_arch = 'armv7l' + elif arch == 'arm64': + tizen_arch = 'aarch64' + elif arch == 'x86': + tizen_arch = 'i686' + else: + sys.exit('Unknown arch: ' + arch) + + base_repo = 'http://download.tizen.org/snapshots/TIZEN/Tizen-{}/Tizen-{}-Base/reference/repos/standard/packages'.format( + api_version, api_version + ) + unified_repo = 'http://download.tizen.org/snapshots/TIZEN/Tizen-{}/Tizen-{}-Unified/reference/repos/standard/packages'.format( + api_version, api_version + ) + + # Retrieve html documents. + documents = {} + for url in ['{}/{}'.format(base_repo, tizen_arch), '{}/{}'.format(base_repo, 'noarch'), + '{}/{}'.format(unified_repo, tizen_arch), '{}/{}'.format(unified_repo, 'noarch')]: + request = urllib.request.Request(url) + with urllib.request.urlopen(request) as response: + documents[url] = response.read().decode('utf-8') + + # Download packages. + download_path = sysroot / '.rpms' + download_path.mkdir(exist_ok=True) + existing_rpms = [f for f in download_path.iterdir() if f.suffix == '.rpm'] + + for package in base_packages + unified_packages: + quoted = urllib.parse.quote(package) + pattern = re.escape(quoted) + '-\\d+\\.[\\d_\\.]+-[\\d\\.]+\\..+\\.rpm' + + if any([re.match(pattern, rpm.name) for rpm in existing_rpms]): + continue + + for parent, doc in documents.items(): + match = re.search('.+?'.format(pattern), doc) + if match: + rpm_url = '{}/{}'.format(parent, match.group(1)) + break + + if match: + if not quiet: + print('Downloading ' + rpm_url) + urllib.request.urlretrieve(rpm_url, download_path / match.group(1)) + else: + sys.exit('Could not find a package named ' + package) + + # Extract files. + for rpm in [f for f in download_path.iterdir() if f.suffix == '.rpm']: + command = 'rpm2cpio {} | cpio -idum --quiet'.format(rpm) + subprocess.run(command, shell=True, cwd=sysroot, check=True) + + # Create symbolic links. + asm = sysroot / 'usr' / 'include' / 'asm' + if not asm.exists(): + os.symlink('asm-' + arch, asm) + pkgconfig = sysroot / 'usr' / 'lib' / 'pkgconfig' + if arch == 'arm64' and not pkgconfig.exists(): + os.symlink('../lib64/pkgconfig', pkgconfig) + + # Copy objects required by the linker, such as crtbeginS.o and libgcc.a. + if arch == 'arm64': + libpath = sysroot / 'usr' / 'lib64' + else: + libpath = sysroot / 'usr' / 'lib' + subprocess.run('cp gcc/*/*/*.o gcc/*/*/*.a .', shell=True, cwd=libpath, check=True) + + # Apply a patch if applicable. + patch = Path(__file__).parent / '{}.patch'.format(arch) + if patch.is_file(): + command = 'patch -p1 -s -d {} < {}'.format(sysroot, patch) + subprocess.run(command, shell=True, check=True) + + +def main(): + # Check dependencies. + for dep in ['rpm2cpio', 'cpio', 'git']: + if not shutil.which(dep): + sys.exit('{} is not installed. To install, run:\n' + ' sudo apt install {}'.format(dep, dep)) + + # Parse arguments. + parser = argparse.ArgumentParser(description='Tizen sysroot generator') + parser.add_argument('-o', '--out', metavar='PATH', type=str, help='Path to the output directory') + parser.add_argument('-f', '--force', action='store_true', help='Force re-downloading of packages') + parser.add_argument('-q', '--quiet', action='store_true', help='Suppress log output') + parser.add_argument( + '--api-version', + metavar='VER', + default=6.0, + type=float, + help='Target API version (defaults to 6.0)' + ) + args = parser.parse_args() + + if args.out: + outpath = Path(args.out) + else: + outpath = Path(__file__).parent / 'sysroot' + outpath.mkdir(exist_ok=True) + + for arch in ['arm', 'arm64', 'x86']: + sysroot = outpath / arch + if args.force and sysroot.is_dir(): + shutil.rmtree(sysroot) + sysroot.mkdir(exist_ok=True) + + if not args.quiet: + print('Generating sysroot for {}...'.format(arch)) + generate_sysroot(sysroot.resolve(), args.api_version, arch, args.quiet) + + +# Execute only if run as a script. +if __name__ == '__main__': + main() diff --git a/engine/src/flutter/common/config.gni b/engine/src/flutter/common/config.gni index 318d305bd37fc..f3b3c15534a2f 100644 --- a/engine/src/flutter/common/config.gni +++ b/engine/src/flutter/common/config.gni @@ -157,6 +157,4 @@ if (flutter_prebuilt_dart_sdk) { # TODO: We can't build the engine artifacts for arm (32-bit) right now; # see https://github.com/flutter/flutter/issues/74322. build_engine_artifacts = - flutter_build_engine_artifacts && !is_android && - (current_toolchain == host_toolchain || - (is_linux && !is_chromeos && current_cpu != "arm") || is_mac || is_win) + flutter_build_engine_artifacts && current_toolchain == host_toolchain diff --git a/engine/src/flutter/display_list/testing/BUILD.gn b/engine/src/flutter/display_list/testing/BUILD.gn index 9a9637184af6f..f3cb22539cf78 100644 --- a/engine/src/flutter/display_list/testing/BUILD.gn +++ b/engine/src/flutter/display_list/testing/BUILD.gn @@ -35,7 +35,8 @@ surface_provider_include_software = !is_android && !is_ios # But, since benchmarks do not run on Windows and rendertests only # runs on SW by default, this restriction currently only limits the # ability to manually cross-check OpenGL on Windows for rendertests -surface_provider_include_gl = !is_fuchsia && !is_ios && !is_win && !is_mac +surface_provider_include_gl = + !is_fuchsia && !is_ios && !is_win && !is_mac && !is_linux # TODO (https://github.com/flutter/flutter/issues/107357): # impeller_enable_vulkan currently requires skia to not use VMA, which in turn diff --git a/engine/src/flutter/impeller/tools/args.gni b/engine/src/flutter/impeller/tools/args.gni index d1b387506a5af..4be3a3d64eb8c 100644 --- a/engine/src/flutter/impeller/tools/args.gni +++ b/engine/src/flutter/impeller/tools/args.gni @@ -18,9 +18,8 @@ declare_args() { enable_unittests) && target_os != "fuchsia" # Whether the Vulkan backend is enabled. - impeller_enable_vulkan = - (is_linux || is_win || is_android || is_mac || is_qnx || - enable_unittests) && target_os != "fuchsia" + impeller_enable_vulkan = (is_linux || is_win || is_android || is_mac || + enable_unittests) && target_os != "fuchsia" } # Arguments that are combinations of other arguments by default but which can diff --git a/engine/src/flutter/impeller/tools/shaders.gni b/engine/src/flutter/impeller/tools/shaders.gni index 98aa5a7932170..ddacd814a83bb 100644 --- a/engine/src/flutter/impeller/tools/shaders.gni +++ b/engine/src/flutter/impeller/tools/shaders.gni @@ -122,22 +122,6 @@ template("impeller_shaders") { analyze = analyze } } - - gles3_shaders = "gles3_$target_name" - - impeller_shaders_gles(gles3_shaders) { - name = invoker.name - require_framebuffer_fetch = require_framebuffer_fetch - gles_language_version = 300 - is_300 = true - analyze = false - if (defined(invoker.gles_exclusions)) { - shaders = invoker.shaders - invoker.gles_exclusions - } else { - shaders = invoker.shaders - } - analyze = analyze - } } if (impeller_enable_vulkan) { @@ -171,12 +155,7 @@ template("impeller_shaders") { } if (enable_opengles) { - public_deps += [ ":$gles3_shaders" ] - - # wasm builds only use GLES3, no need to build GLES2 shaders - if (!is_wasm) { - public_deps += [ ":$gles_shaders" ] - } + public_deps += [ ":$gles_shaders" ] } if (impeller_enable_vulkan) { diff --git a/engine/src/flutter/shell/config.gni b/engine/src/flutter/shell/config.gni index 3f498d2c044f7..8aa62e02417ba 100644 --- a/engine/src/flutter/shell/config.gni +++ b/engine/src/flutter/shell/config.gni @@ -7,7 +7,7 @@ declare_args() { # The logic for enabling Vulkan and Metal is in tools/gn. shell_enable_metal = false - shell_enable_vulkan = false + shell_enable_vulkan = true shell_enable_software = true } @@ -17,6 +17,6 @@ declare_args() { test_enable_metal = shell_enable_metal # The Vulkan unittests are combined with the GL unittests. - test_enable_vulkan = is_fuchsia || shell_enable_gl + test_enable_vulkan = is_fuchsia test_enable_software = shell_enable_software } diff --git a/engine/src/flutter/shell/platform/embedder/BUILD.gn b/engine/src/flutter/shell/platform/embedder/BUILD.gn index de073b38654f6..cda34ae1bb4b5 100644 --- a/engine/src/flutter/shell/platform/embedder/BUILD.gn +++ b/engine/src/flutter/shell/platform/embedder/BUILD.gn @@ -167,6 +167,8 @@ template("embedder_source_set") { if (embedder_enable_vulkan) { sources += [ + "embedder_external_texture_vulkan.cc", + "embedder_external_texture_vulkan.h", "embedder_surface_vulkan.cc", "embedder_surface_vulkan.h", ] @@ -175,6 +177,8 @@ template("embedder_source_set") { sources += [ "embedder_surface_vulkan_impeller.cc", "embedder_surface_vulkan_impeller.h", + "embedder_external_texture_source_vulkan.cc", + "embedder_external_texture_source_vulkan.h", ] } diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index a2e5b51086d86..27390d7239127 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -2345,6 +2345,27 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, external_texture_metal_callback); } } +#endif +#ifdef SHELL_ENABLE_VULKAN + if (config->type == kVulkan) { + const FlutterVulkanRendererConfig* vulkan_config = &config->vulkan; + if (auto callback = SAFE_ACCESS(vulkan_config, + external_texture_frame_callback, nullptr)) { + auto external_texture_vulkan_callback = + [ptr = callback, user_data]( + int64_t texture_identifier, size_t width, + size_t height) -> std::unique_ptr { + std::unique_ptr texture = + std::make_unique(); + if (!ptr(user_data, texture_identifier, width, height, texture.get())) { + return nullptr; + } + return texture; + }; + external_texture_resolver = std::make_unique( + external_texture_vulkan_callback); + } + } #endif auto custom_task_runners = SAFE_ACCESS(args, custom_task_runners, nullptr); auto thread_config_callback = [&custom_task_runners]( diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index 00900d8f39b08..1fd58e5b2f0b9 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -923,6 +923,9 @@ typedef void* FlutterVulkanQueueHandle; /// Alias for VkImage. typedef uint64_t FlutterVulkanImageHandle; +/// Alias for VkDeviceMemory. +typedef uint64_t FlutterVulkanDeviceMemoryHandle; + typedef struct { /// The size of this struct. Must be sizeof(FlutterVulkanImage). size_t struct_size; @@ -951,6 +954,36 @@ typedef bool (*FlutterVulkanPresentCallback)( void* /* user data */, const FlutterVulkanImage* /* image */); +typedef struct { + /// Handle to the VkImage that is owned by the embedder. The engine will + /// bind this image for writing the frame. + FlutterVulkanImageHandle image; + /// The VkDeviceMemory that backs the iamge. + FlutterVulkanDeviceMemoryHandle image_memory; + /// The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM). + uint32_t format; + /// User data to be returned on the invocation of the destruction callback. + void* user_data; + /// Callback invoked (on an engine managed thread) that asks the embedder to + /// collect the texture. + VoidCallback destruction_callback; + /// Optional parameters for texture height/width, default is 0, non-zero means + /// the texture has the specified width/height. + /// Width of the texture. + size_t width; + /// Height of the texture. + size_t height; +} FlutterVulkanTexture; + +/// Callback to provide an external texture for a given texture_id. +/// See: external_texture_frame_callback. +typedef bool (*FlutterVulkanTextureFrameCallback)( + void* /* user data */, + int64_t /* texture identifier */, + size_t /* width */, + size_t /* height */, + FlutterVulkanTexture* /* texture out */); + typedef struct { /// The size of this struct. Must be sizeof(FlutterVulkanRendererConfig). size_t struct_size; @@ -1014,7 +1047,11 @@ typedef struct { /// without any additional synchronization. /// Not used if a FlutterCompositor is supplied in FlutterProjectArgs. FlutterVulkanPresentCallback present_image_callback; - + /// When the embedder specifies that a texture has a frame available, the + /// engine will call this method (on an internal engine managed thread) so + /// that external texture details can be supplied to the engine for subsequent + /// composition. + FlutterVulkanTextureFrameCallback external_texture_frame_callback; } FlutterVulkanRendererConfig; typedef struct { diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc index fe81731aff0d5..3d7c9bba97bfa 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc @@ -27,6 +27,88 @@ namespace flutter { +std::optional TextureLRU::FindTexture( + std::optional key) { + if (!key.has_value()) { + return std::nullopt; + } + auto key_value = key.value(); + for (size_t i = 0u; i < kTextureMaxSize; i++) { + if (textures_[i].key == key_value) { + UpdateTexture(Data{.key = key_value, + .texture = textures_[i].texture, + .width = textures_[i].width, + .height = textures_[i].height}); + return std::make_optional(textures_[i]); + } + } + return std::nullopt; +} + +void TextureLRU::UpdateTexture(Data data) { + if (textures_[0].key == data.key) { + textures_[0] = data; + return; + } + size_t i = 1u; + for (; i < kTextureMaxSize; i++) { + if (textures_[i].key == data.key) { + break; + } + } + + if (i == kTextureMaxSize) { + return; + } + + for (auto j = i; j > 0; j--) { + textures_[j] = textures_[j - 1]; + } + textures_[0] = data; +} + +GLuint TextureLRU::AddTexture(Data data) { + GLuint lru_key = textures_[kTextureMaxSize - 1].key; + bool updated_image = false; + for (size_t i = 0u; i < kTextureMaxSize; i++) { + if (textures_[i].key == lru_key) { + updated_image = true; + textures_[i] = data; + break; + } + } + if (!updated_image) { + textures_[0] = data; + } + UpdateTexture(data); + return lru_key; +} + +void TextureLRU::Clear() { + for (size_t i = 0u; i < kTextureMaxSize; i++) { + textures_[i] = Data{.key = 0u, .texture = nullptr}; + } +} + +void TextureLRU::RemoveTexture(GLuint key) { + size_t i = 0u; + for (; i < kTextureMaxSize; i++) { + if (textures_[i].key == key) { + break; + } + } + + if (i == kTextureMaxSize) { + return; + } + + for (; i < kTextureMaxSize - 1; i++) { + textures_[i] = textures_[i + 1]; + } + + textures_[kTextureMaxSize - 1] = Data{.key = 0u, .texture = nullptr}; +} + EmbedderExternalTextureGL::EmbedderExternalTextureGL( int64_t texture_identifier, const ExternalTextureCallback& callback) @@ -70,8 +152,10 @@ sk_sp EmbedderExternalTextureGL::ResolveTexture( const SkISize& size) { if (!!aiks_context) { return ResolveTextureImpeller(texture_id, aiks_context, size); - } else { + } else if (!!context) { return ResolveTextureSkia(texture_id, context, size); + } else { + return nullptr; } } @@ -127,28 +211,27 @@ sk_sp EmbedderExternalTextureGL::ResolveTextureSkia( return DlImage::Make(std::move(image)); } -sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( - int64_t texture_id, +std::shared_ptr +EmbedderExternalTextureGL::CreateTextureGLES( impeller::AiksContext* aiks_context, - const SkISize& size) { - std::unique_ptr texture = - external_texture_callback_(texture_id, size.width(), size.height()); - - if (!texture) { - return nullptr; - } - + FlutterOpenGLTexture* texture) { impeller::TextureDescriptor desc; desc.size = impeller::ISize(texture->width, texture->height); - + desc.storage_mode = impeller::StorageMode::kDevicePrivate; + desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt; + if (texture->target == GL_TEXTURE_EXTERNAL_OES) { + desc.type = impeller::TextureType::kTextureExternalOES; + } else { + desc.type = impeller::TextureType::kTexture2D; + } impeller::ContextGLES& context = impeller::ContextGLES::Cast(*aiks_context->GetContext()); impeller::HandleGLES handle = context.GetReactor()->CreateHandle( - impeller::HandleType::kTexture, texture->target); - std::shared_ptr image = - impeller::TextureGLES::WrapTexture(context.GetReactor(), desc, handle); + impeller::HandleType::kTexture, texture->name); - if (!image) { + auto gles_texture = + impeller::TextureGLES::WrapTexture(context.GetReactor(), desc, handle); + if (!gles_texture) { // In case Skia rejects the image, call the release proc so that // embedders can perform collection of intermediates. if (texture->destruction_callback) { @@ -157,6 +240,10 @@ sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( FML_LOG(ERROR) << "Could not create external texture"; return nullptr; } + + gles_texture->SetCoordinateSystem( + impeller::TextureCoordinateSystem::kUploadFromHost); + if (texture->destruction_callback && !context.GetReactor()->RegisterCleanupCallback( handle, @@ -165,8 +252,63 @@ sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( FML_LOG(ERROR) << "Could not register destruction callback"; return nullptr; } + return gles_texture; +} + +sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( + int64_t texture_id, + impeller::AiksContext* aiks_context, + const SkISize& size) { + std::unique_ptr texture = + external_texture_callback_(texture_id, size.width(), size.height()); + + if (!texture) { + return nullptr; + } + + std::optional texture_data = + texture_lru_.FindTexture(texture->name); - return impeller::DlImageImpeller::Make(image); + bool size_change = false; + + if (texture_data.has_value() && + (texture_data.value().width != texture->width || + texture_data.value().height != texture->height)) { + size_change = true; + } + + if (texture_data.has_value() && !size_change) { + return impeller::DlImageImpeller::Make(texture_data.value().texture); + } else if (texture_data.has_value() && size_change) { + std::shared_ptr old_gles_texture = + texture_data.value().texture; + old_gles_texture->Leak(); + std::shared_ptr new_gles_texture = + CreateTextureGLES(aiks_context, texture.get()); + if (new_gles_texture) { + texture_lru_.UpdateTexture(TextureLRU::Data{.key = texture->name, + .texture = new_gles_texture, + .width = texture->width, + .height = texture->height}); + + return impeller::DlImageImpeller::Make(new_gles_texture); + } else { + texture_lru_.RemoveTexture(texture->name); + return nullptr; + } + } else { + std::shared_ptr new_gles_texture = + CreateTextureGLES(aiks_context, texture.get()); + if (new_gles_texture) { + texture_lru_.AddTexture(TextureLRU::Data{.key = texture->name, + .texture = new_gles_texture, + .width = texture->width, + .height = texture->height}); + return impeller::DlImageImpeller::Make(new_gles_texture); + } else { + return nullptr; + } + } } // |flutter::Texture| @@ -181,6 +323,8 @@ void EmbedderExternalTextureGL::MarkNewFrameAvailable() { } // |flutter::Texture| -void EmbedderExternalTextureGL::OnTextureUnregistered() {} +void EmbedderExternalTextureGL::OnTextureUnregistered() { + texture_lru_.Clear(); +} } // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h index 7dbc631d56ad1..1fbbb01968a28 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h @@ -5,12 +5,52 @@ #ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_ #define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_ +#include +#include +#include #include "flutter/common/graphics/texture.h" #include "flutter/fml/macros.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "impeller/renderer/backend/gles/texture_gles.h" #include "third_party/skia/include/core/SkSize.h" namespace flutter { +static constexpr size_t kTextureMaxSize = 6u; + +class TextureLRU { + public: + struct Data { + GLuint key = 0u; + std::shared_ptr texture; + size_t width = 0; + size_t height = 0; + }; + + TextureLRU() = default; + + ~TextureLRU() = default; + + /// @brief Retrieve the Texture associated with the given [key], or nullptr. + std::optional FindTexture(std::optional key); + + /// @brief Add a new texture to the cache with a key, returning the key of the + /// LRU entry that was removed. + /// + /// The value may be `0`, in which case nothing was removed. + GLuint AddTexture(Data data); + + /// @brief Remove all entires from the image cache. + void Clear(); + + /// @brief Remove a texture from the cache by key. + void RemoveTexture(GLuint key); + + /// @brief Marks [key] as the most recently used. + void UpdateTexture(Data data); + + private: + std::array textures_; +}; class EmbedderExternalTextureGL : public flutter::Texture { public: @@ -25,7 +65,7 @@ class EmbedderExternalTextureGL : public flutter::Texture { private: const ExternalTextureCallback& external_texture_callback_; sk_sp last_image_; - + TextureLRU texture_lru_ = TextureLRU(); sk_sp ResolveTexture(int64_t texture_id, GrDirectContext* context, impeller::AiksContext* aiks_context, @@ -39,6 +79,10 @@ class EmbedderExternalTextureGL : public flutter::Texture { impeller::AiksContext* aiks_context, const SkISize& size); + std::shared_ptr CreateTextureGLES( + impeller::AiksContext* aiks_context, + FlutterOpenGLTexture* texture); + // |flutter::Texture| void Paint(PaintContext& context, const DlRect& bounds, diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.cc index 4e4b41b8d4ad2..2dcef86b2061c 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.cc @@ -21,6 +21,12 @@ EmbedderExternalTextureResolver::EmbedderExternalTextureResolver( : metal_callback_(std::move(metal_callback)) {} #endif +#ifdef SHELL_ENABLE_VULKAN +EmbedderExternalTextureResolver::EmbedderExternalTextureResolver( + EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback) + : vulkan_callback_(std::move(vulkan_callback)) {} +#endif + std::unique_ptr EmbedderExternalTextureResolver::ResolveExternalTexture(int64_t texture_id) { #ifdef SHELL_ENABLE_GL @@ -37,6 +43,13 @@ EmbedderExternalTextureResolver::ResolveExternalTexture(int64_t texture_id) { } #endif +#ifdef SHELL_ENABLE_VULKAN + if (vulkan_callback_) { + return std::make_unique(texture_id, + vulkan_callback_); + } +#endif + return nullptr; } @@ -53,6 +66,12 @@ bool EmbedderExternalTextureResolver::SupportsExternalTextures() { } #endif +#ifdef SHELL_ENABLE_VULKAN + if (vulkan_callback_) { + return true; + } +#endif + return false; } diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.h b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.h index 412301736e566..1079a006d6359 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.h @@ -17,6 +17,10 @@ #include "flutter/shell/platform/embedder/embedder_external_texture_metal.h" #endif +#ifdef SHELL_ENABLE_VULKAN +#include "flutter/shell/platform/embedder/embedder_external_texture_vulkan.h" +#endif + namespace flutter { class EmbedderExternalTextureResolver { public: @@ -34,6 +38,11 @@ class EmbedderExternalTextureResolver { EmbedderExternalTextureMetal::ExternalTextureCallback metal_callback); #endif +#ifdef SHELL_ENABLE_VULKAN + explicit EmbedderExternalTextureResolver( + EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback); +#endif + std::unique_ptr ResolveExternalTexture(int64_t texture_id); bool SupportsExternalTextures(); @@ -47,6 +56,9 @@ class EmbedderExternalTextureResolver { EmbedderExternalTextureMetal::ExternalTextureCallback metal_callback_; #endif +#ifdef SHELL_ENABLE_VULKAN + EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback_; +#endif FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureResolver); }; } // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.cc new file mode 100644 index 0000000000000..31a959f9ba0c5 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.cc @@ -0,0 +1,204 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h" + +#include "impeller/renderer/backend/vulkan/allocator_vk.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/texture_source_vk.h" +#include "impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h" +#include "vulkan/vulkan.hpp" + +namespace flutter { + +bool RequiresYCBCRConversion(impeller::vk::Format format) { + switch (format) { + case impeller::vk::Format::eG8B8R83Plane420Unorm: + case impeller::vk::Format::eG8B8R82Plane420Unorm: + case impeller::vk::Format::eG8B8R83Plane422Unorm: + case impeller::vk::Format::eG8B8R82Plane422Unorm: + case impeller::vk::Format::eG8B8R83Plane444Unorm: + return true; + default: + // NOTE: NOT EXHAUSTIVE. + break; + } + return false; +} + +EmbedderExternalTextureSourceVulkan::EmbedderExternalTextureSourceVulkan( + const std::shared_ptr& p_context, + FlutterVulkanTexture* embedder_desc) + : TextureSourceVK(ToTextureDescriptor(embedder_desc)) { + const auto& context = impeller::ContextVK::Cast(*p_context); + const auto& device = context.GetDevice(); + texture_image_ = + impeller::vk::Image(reinterpret_cast(embedder_desc->image)); + texture_device_memory_ = impeller::vk::DeviceMemory( + reinterpret_cast(embedder_desc->image_memory)); + + needs_yuv_conversion_ = RequiresYCBCRConversion( + static_cast(embedder_desc->format)); + std::shared_ptr yuv_conversion; + if (needs_yuv_conversion_) { + // Figure out how to perform YUV conversions. + yuv_conversion = CreateYUVConversion(context, embedder_desc); + if (!yuv_conversion || !yuv_conversion->IsValid()) { + VALIDATION_LOG << "Fail to create yuv conversion"; + return; + } + } + + // Create image view for the newly created image. + if (!CreateTextureImageView(device, embedder_desc, yuv_conversion)) { + VALIDATION_LOG << "Fail to create texture image view"; + return; + } + + yuv_conversion_ = std::move(yuv_conversion); + is_valid_ = true; +} + +impeller::PixelFormat ToPixelFormat(int32_t vk_format) { + switch (vk_format) { + case VK_FORMAT_UNDEFINED: + return impeller::PixelFormat::kUnknown; + case VK_FORMAT_R8G8B8A8_UNORM: + return impeller::PixelFormat::kR8G8B8A8UNormInt; + case VK_FORMAT_R8G8B8A8_SRGB: + return impeller::PixelFormat::kR8G8B8A8UNormIntSRGB; + case VK_FORMAT_B8G8R8A8_UNORM: + return impeller::PixelFormat::kB8G8R8A8UNormInt; + case VK_FORMAT_B8G8R8A8_SRGB: + return impeller::PixelFormat::kB8G8R8A8UNormIntSRGB; + case VK_FORMAT_R32G32B32A32_SFLOAT: + return impeller::PixelFormat::kR32G32B32A32Float; + case VK_FORMAT_R16G16B16A16_SFLOAT: + return impeller::PixelFormat::kR16G16B16A16Float; + case VK_FORMAT_S8_UINT: + return impeller::PixelFormat::kS8UInt; + case VK_FORMAT_D24_UNORM_S8_UINT: + return impeller::PixelFormat::kD24UnormS8Uint; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return impeller::PixelFormat::kD32FloatS8UInt; + case VK_FORMAT_R8_UNORM: + return impeller::PixelFormat::kR8UNormInt; + case VK_FORMAT_R8G8_UNORM: + return impeller::PixelFormat::kR8G8UNormInt; + default: + return impeller::PixelFormat::kUnknown; + } +} + +impeller::TextureDescriptor +EmbedderExternalTextureSourceVulkan::ToTextureDescriptor( + FlutterVulkanTexture* embedder_desc) { + const auto size = + impeller::ISize{static_cast(embedder_desc->width), + static_cast(embedder_desc->height)}; + impeller::TextureDescriptor desc; + desc.storage_mode = impeller::StorageMode::kDevicePrivate; + desc.format = ToPixelFormat(embedder_desc->format); + desc.size = size; + desc.type = impeller::TextureType::kTexture2D; + desc.sample_count = impeller::SampleCount::kCount1; + desc.compression_type = impeller::CompressionType::kLossless; + desc.mip_count = 1u; + desc.usage = impeller::TextureUsage::kRenderTarget; + return desc; +} + +std::shared_ptr +EmbedderExternalTextureSourceVulkan::CreateYUVConversion( + const impeller::ContextVK& context, + FlutterVulkanTexture* embedder_desc) { + impeller::YUVConversionDescriptorVK conversion_chain; + auto& conversion_info = conversion_chain.get(); + + conversion_info.format = + static_cast(embedder_desc->format); + conversion_info.ycbcrModel = + impeller::vk::SamplerYcbcrModelConversion::eYcbcr709; + conversion_info.ycbcrRange = impeller::vk::SamplerYcbcrRange::eItuFull; + conversion_info.components = {impeller::vk::ComponentSwizzle::eIdentity, + impeller::vk::ComponentSwizzle::eIdentity, + impeller::vk::ComponentSwizzle::eIdentity, + impeller::vk::ComponentSwizzle::eIdentity}; + conversion_info.xChromaOffset = impeller::vk::ChromaLocation::eCositedEven; + conversion_info.yChromaOffset = impeller::vk::ChromaLocation::eCositedEven; + conversion_info.chromaFilter = impeller::vk::Filter::eNearest; + conversion_info.forceExplicitReconstruction = false; + return context.GetYUVConversionLibrary()->GetConversion(conversion_chain); +} + +bool EmbedderExternalTextureSourceVulkan::CreateTextureImageView( + const impeller::vk::Device& device, + FlutterVulkanTexture* embedder_desc, + const std::shared_ptr& yuv_conversion_wrapper) { + impeller::vk::StructureChain + view_chain; + auto& view_info = view_chain.get(); + view_info.image = texture_image_; + view_info.viewType = impeller::vk::ImageViewType::e2D; + view_info.format = static_cast(embedder_desc->format); + view_info.subresourceRange.aspectMask = + impeller::vk::ImageAspectFlagBits::eColor; + view_info.subresourceRange.baseMipLevel = 0u; + view_info.subresourceRange.baseArrayLayer = 0u; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.layerCount = 1; + + if (RequiresYCBCRConversion( + static_cast(embedder_desc->format))) { + view_chain.get().conversion = + yuv_conversion_wrapper->GetConversion(); + } else { + view_chain.unlink(); + } + auto image_view = device.createImageViewUnique(view_info); + if (image_view.result != impeller::vk::Result::eSuccess) { + return false; + } + texture_image_view_ = std::move(image_view.value); + return true; +} + +// |TextureSourceVK| +EmbedderExternalTextureSourceVulkan::~EmbedderExternalTextureSourceVulkan() = + default; + +bool EmbedderExternalTextureSourceVulkan::IsValid() const { + return is_valid_; +} + +// |TextureSourceVK| +impeller::vk::Image EmbedderExternalTextureSourceVulkan::GetImage() const { + return texture_image_; +} + +// |TextureSourceVK| +impeller::vk::ImageView EmbedderExternalTextureSourceVulkan::GetImageView() + const { + return texture_image_view_.get(); +} + +// |TextureSourceVK| +impeller::vk::ImageView +EmbedderExternalTextureSourceVulkan::GetRenderTargetView() const { + return texture_image_view_.get(); +} + +// |TextureSourceVK| +bool EmbedderExternalTextureSourceVulkan::IsSwapchainImage() const { + return is_swapchain_image_; +} + +// |TextureSourceVK| +std::shared_ptr +EmbedderExternalTextureSourceVulkan::GetYUVConversion() const { + return needs_yuv_conversion_ ? yuv_conversion_ : nullptr; +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h new file mode 100644 index 0000000000000..57bad4034fe59 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h @@ -0,0 +1,70 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_SOURCE_VULKAN_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_SOURCE_VULKAN_H_ + +#include "flutter/shell/platform/embedder/embedder.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/texture_source_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/backend/vulkan/yuv_conversion_vk.h" + +namespace flutter { + +class ContextVK; + +class EmbedderExternalTextureSourceVulkan final + : public impeller::TextureSourceVK { + public: + EmbedderExternalTextureSourceVulkan( + const std::shared_ptr& context, + FlutterVulkanTexture* embedder_desc); + + // |TextureSourceVK| + ~EmbedderExternalTextureSourceVulkan() override; + + // |TextureSourceVK| + impeller::vk::Image GetImage() const override; + + // |TextureSourceVK| + impeller::vk::ImageView GetImageView() const override; + + // |TextureSourceVK| + impeller::vk::ImageView GetRenderTargetView() const override; + + bool IsValid() const; + + // |TextureSourceVK| + bool IsSwapchainImage() const override; + + // |TextureSourceVK| + std::shared_ptr GetYUVConversion() const override; + + private: + bool CreateTextureImageView( + const impeller::vk::Device& device, + FlutterVulkanTexture* embedder_desc, + const std::shared_ptr& yuv_conversion_wrapper); + impeller::TextureDescriptor ToTextureDescriptor( + FlutterVulkanTexture* embedder_desc); + std::shared_ptr CreateYUVConversion( + const impeller::ContextVK& context, + FlutterVulkanTexture* embedder_desc); + std::shared_ptr yuv_conversion_ = {}; + bool needs_yuv_conversion_ = false; + bool is_swapchain_image_ = false; + bool is_valid_ = false; + impeller::vk::Image texture_image_; + impeller::vk::DeviceMemory texture_device_memory_; + impeller::vk::UniqueImageView texture_image_view_ = {}; + EmbedderExternalTextureSourceVulkan( + const EmbedderExternalTextureSourceVulkan&) = delete; + EmbedderExternalTextureSourceVulkan& operator=( + const EmbedderExternalTextureSourceVulkan&) = delete; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_SOURCE_VULKAN_H_ diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.cc new file mode 100644 index 0000000000000..b50d9644b914a --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.cc @@ -0,0 +1,195 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/embedder/embedder_external_texture_vulkan.h" + +#include "flutter/fml/logging.h" +#include "flutter/impeller/display_list/dl_image_impeller.h" +#include "flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include "flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h" +#include "impeller/core/texture_descriptor.h" +#include "impeller/display_list/aiks_context.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/renderer/context.h" +#include "include/core/SkCanvas.h" +#include "include/core/SkPaint.h" +#include "third_party/skia/include/core/SkAlphaType.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkColorType.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSize.h" +#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h" +#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h" +#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h" +#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h" +#include "third_party/skia/include/gpu/ganesh/vk/GrVkTypes.h" + +namespace flutter { +EmbedderExternalTextureVulkan::EmbedderExternalTextureVulkan( + int64_t texture_identifier, + const ExternalTextureCallback& callback) + : Texture(texture_identifier), external_texture_callback_(callback) { + FML_DCHECK(external_texture_callback_); +} + +// |flutter::Texture| +void EmbedderExternalTextureVulkan::Paint(PaintContext& context, + const DlRect& bounds, + bool freeze, + const DlImageSampling sampling) { + if (last_image_ == nullptr) { + last_image_ = + ResolveTexture(Id(), context.gr_context, context.aiks_context, + SkISize::Make(bounds.GetWidth(), bounds.GetHeight())); + } + + DlCanvas* canvas = context.canvas; + const DlPaint* paint = context.paint; + + if (last_image_) { + DlRect image_bounds = DlRect::Make(last_image_->GetBounds()); + if (bounds != image_bounds) { + canvas->DrawImageRect(last_image_, image_bounds, bounds, sampling, paint); + } else { + canvas->DrawImage(last_image_, bounds.GetOrigin(), sampling, paint); + } + } +} + +sk_sp EmbedderExternalTextureVulkan::ResolveTexture( + int64_t texture_id, + GrDirectContext* context, + impeller::AiksContext* aiks_context, + const SkISize& size) { + if (!!aiks_context) { + return ResolveTextureImpeller(texture_id, aiks_context, size); + } else { + return ResolveTextureSkia(texture_id, context, size); + } +} + +sk_sp EmbedderExternalTextureVulkan::ResolveTextureSkia( + int64_t texture_id, + GrDirectContext* context, + const SkISize& size) { + context->flushAndSubmit(); + context->resetContext(kAll_GrBackendState); + std::unique_ptr texture = + external_texture_callback_(texture_id, size.width(), size.height()); + + if (!texture) { + return nullptr; + } + + size_t width = size.width(); + size_t height = size.height(); + + if (texture->width != 0 && texture->height != 0) { + width = texture->width; + height = texture->height; + } + + GrVkImageInfo image_info = { + .fImage = reinterpret_cast(texture->image), + .fImageTiling = VK_IMAGE_TILING_OPTIMAL, + .fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .fFormat = static_cast(texture->format), + .fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + .fSampleCount = 1, + .fLevelCount = 1, + }; + + auto gr_backend_texture = + GrBackendTextures::MakeVk(width, height, image_info); + SkImages::TextureReleaseProc release_proc = texture->destruction_callback; + auto image = + SkImages::BorrowTextureFrom(context, // context + gr_backend_texture, // texture handle + kTopLeft_GrSurfaceOrigin, // origin + kRGB_888x_SkColorType, // color type + kPremul_SkAlphaType, // alpha type + nullptr, // colorspace + release_proc, // texture release proc + texture->user_data // texture release context + ); + + if (!image) { + // In case Skia rejects the image, call the release proc so that + // embedders can perform collection of intermediates. + if (release_proc) { + release_proc(texture->user_data); + } + return nullptr; + } + + return DlImage::Make(std::move(image)); +} + +sk_sp EmbedderExternalTextureVulkan::ResolveTextureImpeller( + int64_t texture_id, + impeller::AiksContext* aiks_context, + const SkISize& size) { + std::unique_ptr texture_desc = + external_texture_callback_(texture_id, size.width(), size.height()); + if (!texture_desc) { + return nullptr; + } + + auto& impeller_context = + impeller::ContextVK::Cast(*aiks_context->GetContext()); + + auto texture_source = std::make_shared( + aiks_context->GetContext(), texture_desc.get()); + + auto texture = std::make_shared( + aiks_context->GetContext(), texture_source); + // Transition the layout to shader read. + { + auto buffer = impeller_context.CreateCommandBuffer(); + impeller::CommandBufferVK& buffer_vk = + impeller::CommandBufferVK::Cast(*buffer); + + impeller::BarrierVK barrier; + barrier.cmd_buffer = buffer_vk.GetCommandBuffer(); + barrier.src_access = impeller::vk::AccessFlagBits::eColorAttachmentWrite | + impeller::vk::AccessFlagBits::eTransferWrite; + barrier.src_stage = + impeller::vk::PipelineStageFlagBits::eColorAttachmentOutput | + impeller::vk::PipelineStageFlagBits::eTransfer; + barrier.dst_access = impeller::vk::AccessFlagBits::eShaderRead; + barrier.dst_stage = impeller::vk::PipelineStageFlagBits::eFragmentShader; + + barrier.new_layout = impeller::vk::ImageLayout::eShaderReadOnlyOptimal; + + if (!texture_source->SetLayout(barrier).ok()) { + return nullptr; + } + if (!impeller_context.GetCommandQueue()->Submit({buffer}).ok()) { + return nullptr; + } + } + impeller_context.DisposeThreadLocalCachedResources(); + return impeller::DlImageImpeller::Make(texture); +} + +EmbedderExternalTextureVulkan::~EmbedderExternalTextureVulkan() = default; + +// |flutter::Texture| +void EmbedderExternalTextureVulkan::OnGrContextCreated() {} + +// |flutter::Texture| +void EmbedderExternalTextureVulkan::OnGrContextDestroyed() {} + +// |flutter::Texture| +void EmbedderExternalTextureVulkan::MarkNewFrameAvailable() { + last_image_ = nullptr; +} + +// |flutter::Texture| +void EmbedderExternalTextureVulkan::OnTextureUnregistered() {} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.h b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.h new file mode 100644 index 0000000000000..07611b4b729bf --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_vulkan.h @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_VULKAN_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_VULKAN_H_ + +#include "flutter/common/graphics/texture.h" +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "include/core/SkTypes.h" +#include "include/gpu/vk/VulkanTypes.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace flutter { + +class EmbedderExternalTextureVulkan : public flutter::Texture { + public: + using ExternalTextureCallback = std::function< + std::unique_ptr(int64_t, size_t, size_t)>; + EmbedderExternalTextureVulkan(int64_t texture_identifier, + const ExternalTextureCallback& callback); + + ~EmbedderExternalTextureVulkan(); + + private: + const ExternalTextureCallback& external_texture_callback_; + + sk_sp last_image_; + + sk_sp ResolveTexture(int64_t texture_id, + GrDirectContext* context, + impeller::AiksContext* aiks_context, + const SkISize& size); + sk_sp ResolveTextureSkia(int64_t texture_id, + GrDirectContext* context, + const SkISize& size); + sk_sp ResolveTextureImpeller(int64_t texture_id, + impeller::AiksContext* aiks_context, + const SkISize& size); + + // |flutter::Texture| + void Paint(PaintContext& context, + const DlRect& bounds, + bool freeze, + const DlImageSampling sampling) override; + + // |flutter::Texture| + void OnGrContextCreated() override; + + // |flutter::Texture| + void OnGrContextDestroyed() override; + + // |flutter::Texture| + void MarkNewFrameAvailable() override; + + // |flutter::Texture| + void OnTextureUnregistered() override; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureVulkan); +}; +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_VULKAN_H_ diff --git a/engine/src/flutter/testing/BUILD.gn b/engine/src/flutter/testing/BUILD.gn index 4cf0a3a6b3a63..30bb7bd7620f0 100644 --- a/engine/src/flutter/testing/BUILD.gn +++ b/engine/src/flutter/testing/BUILD.gn @@ -54,7 +54,7 @@ source_set("testing") { if (enable_unittests && is_linux) { # So that we can call gtk_init in main(). - configs += [ "//flutter/shell/platform/linux/config:gtk" ] + # configs += [ "//flutter/shell/platform/linux/config:gtk" ] } public_deps = [ ":testing_lib" ] diff --git a/engine/src/flutter/testing/testing.gni b/engine/src/flutter/testing/testing.gni index 5ead3d22e922c..c25746c779cec 100644 --- a/engine/src/flutter/testing/testing.gni +++ b/engine/src/flutter/testing/testing.gni @@ -15,7 +15,8 @@ declare_args() { # * host_toolchain: non-cross-compile. We can run tests on the host. # * Fuchsia: build unittests for testing on device. # * macOS: arm64 builds can run x64 binaries. - enable_unittests = current_toolchain == host_toolchain || is_fuchsia || is_mac + # Disable unit test + enable_unittests = false # Build iOS target device unit tests. # diff --git a/engine/src/flutter/tools/gn b/engine/src/flutter/tools/gn index 06a3e28989eeb..3de39014d3507 100755 --- a/engine/src/flutter/tools/gn +++ b/engine/src/flutter/tools/gn @@ -89,18 +89,7 @@ def to_command_line(gn_args): def is_host_build(args): - # If target_os == None, then this is a host build. - if args.target_os is None: - return True - # For linux arm64 builds, we cross compile from x64 hosts, so the - # target_os='linux' and linux-cpu='arm64' - if args.target_os == 'linux' and args.linux_cpu == 'arm64': - return True - # The Mac and host targets are redundant. Again, necessary to disambiguate - # during cross-compilation. - if args.target_os == 'mac': - return True - return False + return args.target_os is None # Determines whether a prebuilt Dart SDK can be used instead of building one. @@ -542,7 +531,7 @@ def to_gn_args(args): # does not exist. Further, we set the 'host_cpu' so that it shares the # bitwidth of the 32-bit arm target. if sys.platform.startswith( - ('cygwin', 'win')) and args.target_os == 'android' and gn_args['target_cpu'] == 'arm': + ('cygwin', 'win')) and args.target_os != 'win' and gn_args['target_cpu'] == 'arm': gn_args['host_cpu'] = 'x86' gn_args['current_cpu'] = 'x86' @@ -773,13 +762,17 @@ def to_gn_args(args): # Enable pointer compression on 64-bit mobile targets. iOS is excluded due to # its inability to allocate address space without allocating memory. - if args.target_os in ['android'] and gn_args['target_cpu'] in ['x64', 'arm64']: + if args.target_os in ['android', 'linux'] and gn_args['target_cpu'] in ['x64', 'arm64']: gn_args['dart_use_compressed_pointers'] = True if args.target_os == 'fuchsia': gn_args['gn_configs_path'] = '//flutter/build/config/fuchsia/gn_configs.gni' gn_args['fuchsia_gn_sdk'] = '//flutter/tools/fuchsia/gn-sdk' + # Don't use the default Linux sysroot when buliding for Linux on macOS. + if sys.platform == 'darwin' and args.target_os == 'linux': + gn_args['use_default_linux_sysroot'] = False + # Flags for Dart features: if args.use_mallinfo2: gn_args['dart_use_mallinfo2'] = args.use_mallinfo2 @@ -805,9 +798,8 @@ def to_gn_args(args): # gen_snapshot, but the build defines otherwise make it look like the build is # for a host Windows build and make GN think we will be building ANGLE. # Angle is not used on Mac hosts as there are no tests for the OpenGL backend. - if is_host_build(args) or (args.target_os == 'android' and get_host_os() == 'win'): - # Don't include git commit information. - gn_args['angle_enable_commit_id'] = False + if (is_host_build(args) and gn_args['host_os'] != 'mac') or (args.target_os == 'linux' and + get_host_os() == 'win'): # Do not build unnecessary parts of the ANGLE tree. gn_args['angle_build_all'] = False gn_args['angle_has_astc_encoder'] = False diff --git a/engine/src/flutter/txt/src/txt/platform_linux.cc b/engine/src/flutter/txt/src/txt/platform_linux.cc index c67f65dbe9829..a20febd4bb6f2 100644 --- a/engine/src/flutter/txt/src/txt/platform_linux.cc +++ b/engine/src/flutter/txt/src/txt/platform_linux.cc @@ -20,8 +20,7 @@ namespace txt { std::vector GetDefaultFontFamilies() { - return {"Ubuntu", "Adwaita Sans", "Cantarell", - "DejaVu Sans", "Liberation Sans", "Arial"}; + return {"TizenDefaultFont", "SamsungOneUI"}; } sk_sp GetDefaultFontManager(uint32_t font_initialization_data) {