Compare commits
6 Commits
ebridgewat
...
ebridgewat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f43aba2a9 | ||
|
|
8a3bf04eef | ||
|
|
44840a481e | ||
|
|
8070643ba5 | ||
|
|
0c33f9f2a3 | ||
|
|
db72bd024b |
7
.github/actions/dep-versions/action.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
name: 'Set up dependency versions'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set up dependency versions
|
||||||
|
shell: bash
|
||||||
|
run: cat ./build/common/versions >> $GITHUB_ENV
|
||||||
38
.github/actions/linux-prereq/action.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: 'Linux Preqrequisites'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- uses: ./.github/actions/dep-versions
|
||||||
|
- name: Install Linux Prerequisites
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -xe
|
||||||
|
# See https://askubuntu.com/questions/272248/processing-triggers-for-man-db/1476024#1476024
|
||||||
|
echo "set man-db/auto-update false" | sudo debconf-communicate
|
||||||
|
sudo dpkg-reconfigure man-db
|
||||||
|
|
||||||
|
# Install ninja
|
||||||
|
source ./build/common/get-ninja.sh
|
||||||
|
|
||||||
|
# Install CMake
|
||||||
|
mkdir -p cmake
|
||||||
|
cd cmake
|
||||||
|
|
||||||
|
sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||||
|
sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||||
|
sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
|
||||||
|
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||||
|
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||||
|
|
||||||
|
# For dawn
|
||||||
|
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
||||||
|
|
||||||
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||||
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||||
|
set +xe
|
||||||
23
.github/actions/mac-prereq/action.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: 'Mac Preqrequisites'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- uses: ./.github/actions/dep-versions
|
||||||
|
- name: Set up Homebrew
|
||||||
|
id: set-up-homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Brew
|
||||||
|
id: brew-cache
|
||||||
|
uses: actions/cache@v4 # Use a specific version
|
||||||
|
with:
|
||||||
|
path: $HOME/Library/Caches/Homebrew
|
||||||
|
key: ${{ runner.os }}-brew-20250424
|
||||||
|
- name: Install Mac Prerequisites
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Install ninja
|
||||||
|
source ./build/common/get-ninja.sh
|
||||||
3
.github/workflows/android-continuous.yml
vendored
@@ -16,6 +16,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run Android Continuous
|
- name: Run Android Continuous
|
||||||
uses: ./.github/actions/android-continuous
|
uses: ./.github/actions/android-continuous
|
||||||
with:
|
with:
|
||||||
|
|||||||
3
.github/workflows/ios-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/ios && printf "y" | ./build.sh continuous
|
cd build/ios && printf "y" | ./build.sh continuous
|
||||||
|
|||||||
3
.github/workflows/linux-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/linux && printf "y" | ./build.sh continuous
|
cd build/linux && printf "y" | ./build.sh continuous
|
||||||
|
|||||||
3
.github/workflows/mac-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/mac && printf "y" | ./build.sh continuous
|
cd build/mac && printf "y" | ./build.sh continuous
|
||||||
|
|||||||
82
.github/workflows/presubmit.yml
vendored
@@ -9,22 +9,32 @@ on:
|
|||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-desktop:
|
build-desktop-mac:
|
||||||
name: build-desktop
|
name: build-mac
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: macos-14-xlarge
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [macos-14-xlarge, ubuntu-22.04-16core]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
cd build/mac && printf "y" | ./build.sh presubmit
|
||||||
cd build/$WORKFLOW_OS && printf "y" | ./build.sh presubmit
|
- name: Test material parser
|
||||||
|
run: |
|
||||||
|
out/cmake-release/filament/test/test_material_parser
|
||||||
|
|
||||||
|
build-desktop-linux:
|
||||||
|
name: build-linux
|
||||||
|
runs-on: ubuntu-22.04-16core
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
|
- name: Run build script
|
||||||
|
run: |
|
||||||
|
cd build/linux && printf "y" | ./build.sh presubmit
|
||||||
- name: Test material parser
|
- name: Test material parser
|
||||||
run: |
|
run: |
|
||||||
out/cmake-release/filament/test/test_material_parser
|
out/cmake-release/filament/test/test_material_parser
|
||||||
@@ -35,6 +45,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
build\windows\build-github.bat presubmit
|
build\windows\build-github.bat presubmit
|
||||||
@@ -48,6 +60,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
@@ -66,6 +79,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/ios && printf "y" | ./build.sh presubmit
|
cd build/ios && printf "y" | ./build.sh presubmit
|
||||||
@@ -79,6 +93,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/web && printf "y" | ./build.sh presubmit
|
cd build/web && printf "y" | ./build.sh presubmit
|
||||||
@@ -101,30 +118,20 @@ jobs:
|
|||||||
runs-on: macos-14-xlarge
|
runs-on: macos-14-xlarge
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
- name: Set up Homebrew
|
|
||||||
id: set-up-homebrew
|
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Cache Mesa and deps
|
- name: Cache Mesa and deps
|
||||||
id: mesa-cache
|
id: mesa-cache
|
||||||
uses: actions/cache@v4 # Use a specific version
|
uses: actions/cache@v4 # Use a specific version
|
||||||
with:
|
with:
|
||||||
path: |
|
path: mesa
|
||||||
$HOME/Library/Caches/Homebrew
|
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
|
||||||
mesa
|
|
||||||
key: ${{ runner.os }}-mesa-deps-${{ vars.MESA_VERSION }}
|
|
||||||
- name: Get Mesa
|
- name: Get Mesa
|
||||||
id: mesa-prereq
|
id: mesa-prereq
|
||||||
env:
|
run: bash test/utils/get_mesa.sh
|
||||||
MESA_VERSION: ${{ vars.MESA_VERSION }}
|
|
||||||
run: |
|
|
||||||
bash test/utils/get_mesa.sh
|
|
||||||
- name: Run Test
|
- name: Run Test
|
||||||
run: |
|
run: bash test/renderdiff/test.sh
|
||||||
bash test/renderdiff/test.sh
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: presubmit-renderdiff-result
|
name: presubmit-renderdiff-result
|
||||||
@@ -133,11 +140,13 @@ jobs:
|
|||||||
validate-wgsl-webgpu:
|
validate-wgsl-webgpu:
|
||||||
name: validate-wgsl-webgpu
|
name: validate-wgsl-webgpu
|
||||||
runs-on: 'ubuntu-24.04-8core'
|
runs-on: 'ubuntu-24.04-8core'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
run: ./build.sh -W debug test_filamat filament
|
||||||
- name: Run test
|
- name: Run test
|
||||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||||
|
|
||||||
@@ -148,23 +157,16 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Homebrew
|
- uses: ./.github/actions/mac-prereq
|
||||||
id: set-up-homebrew
|
- name: Install clang-tidy and deps
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install prerequisites
|
|
||||||
run: |
|
run: |
|
||||||
pip install pyyaml
|
pip install pyyaml
|
||||||
brew install llvm
|
brew install llvm@${GITHUB_LLVM_VERSION}
|
||||||
sudo ln -s "$(brew --prefix llvm)/bin/clang-tidy" "/usr/local/bin/clang-tidy"
|
sudo ln -s "$(brew --prefix llvm)@${GITHUB_LLVM_VERSION}/bin/clang-tidy" "/usr/local/bin/clang-tidy"
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
# We need to build before clang-tidy can run analysis
|
# We need to build before clang-tidy can run analysis
|
||||||
run: |
|
run: |
|
||||||
# This will build for all three desktop backends on mac
|
# This will build for all three desktop backends on mac
|
||||||
./build.sh -p desktop debug gltf_viewer
|
./build.sh -p desktop debug gltf_viewer
|
||||||
- name: Run test
|
- name: Run test
|
||||||
run: |
|
run: bash test/code-correctness/test.sh
|
||||||
bash test/code-correctness/test.sh
|
|
||||||
|
|||||||
48
.github/workflows/release.yml
vendored
@@ -29,8 +29,42 @@ on:
|
|||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-desktop:
|
build-linux:
|
||||||
name: build-desktop
|
name: build-linux
|
||||||
|
runs-on: ubuntu-22.04-32core
|
||||||
|
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Decide Git ref
|
||||||
|
id: git_ref
|
||||||
|
run: |
|
||||||
|
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||||
|
TAG=${REF##*/}
|
||||||
|
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||||
|
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||||
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
ref: ${{ steps.git_ref.outputs.ref }}
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
|
- name: Run build script
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
cd build/linux && printf "y" | ./build.sh release
|
||||||
|
cd ../..
|
||||||
|
mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz
|
||||||
|
- uses: actions/github-script@v6
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const upload = require('./build/common/upload-release-assets');
|
||||||
|
const { TAG } = process.env;
|
||||||
|
const globber = await glob.create('out/*.tgz');
|
||||||
|
await upload({ github, context }, await globber.glob(), TAG);
|
||||||
|
|
||||||
|
build-mac:
|
||||||
|
name: build-mac
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||||
|
|
||||||
@@ -49,15 +83,14 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.git_ref.outputs.ref }}
|
ref: ${{ steps.git_ref.outputs.ref }}
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
run: |
|
run: |
|
||||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
cd build/mac && printf "y" | ./build.sh release
|
||||||
cd build/$WORKFLOW_OS && printf "y" | ./build.sh release
|
|
||||||
cd ../..
|
cd ../..
|
||||||
if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
|
mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz
|
||||||
if [ -f out/filament-release-linux.tgz ]; then mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz; fi;
|
|
||||||
- uses: actions/github-script@v6
|
- uses: actions/github-script@v6
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
@@ -84,6 +117,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.git_ref.outputs.ref }}
|
ref: ${{ steps.git_ref.outputs.ref }}
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
@@ -121,6 +155,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
@@ -171,6 +206,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.git_ref.outputs.ref }}
|
ref: ${{ steps.git_ref.outputs.ref }}
|
||||||
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
|
|||||||
3
.github/workflows/web-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: ./.github/actions/linux-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/web && printf "y" | ./build.sh continuous
|
cd build/web && printf "y" | ./build.sh continuous
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ echo "Please refer to BUILDING.md for more information."
|
|||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
read -r -p "Do you wish to proceed (y/n)? " choice
|
||||||
case "${choice}" in
|
case "${choice}" in
|
||||||
y|Y)
|
y|Y)
|
||||||
echo "Build will proceed..."
|
echo "Build will proceed..."
|
||||||
;;
|
;;
|
||||||
n|N)
|
n|N)
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -30,30 +30,27 @@ set -x
|
|||||||
UNAME=`echo $(uname)`
|
UNAME=`echo $(uname)`
|
||||||
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
|
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
|
||||||
|
|
||||||
FILAMENT_ANDROID_CI_BUILD=true
|
|
||||||
|
|
||||||
# build-common.sh will generate the following variables:
|
# build-common.sh will generate the following variables:
|
||||||
# $GENERATE_ARCHIVES
|
# $GENERATE_ARCHIVES
|
||||||
# $BUILD_DEBUG
|
# $BUILD_DEBUG
|
||||||
# $BUILD_RELEASE
|
# $BUILD_RELEASE
|
||||||
source `dirname $0`/../common/ci-common.sh
|
source `dirname $0`/../common/ci-common.sh
|
||||||
if [[ "$LC_UNAME" == "linux" ]]; then
|
|
||||||
source `dirname $0`/../linux/ci-common.sh
|
|
||||||
elif [[ "$LC_UNAME" == "darwin" ]]; then
|
|
||||||
source `dirname $0`/../mac/ci-common.sh
|
|
||||||
fi
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
java_version=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1)
|
java_version=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1)
|
||||||
if [[ "$java_version" < 17 ]]; then
|
if [[ "$java_version" < 17 ]]; then
|
||||||
echo "Android builds require Java 17, found version ${java_version} instead"
|
echo "Android builds require Java 17, found version ${java_version} instead"
|
||||||
exit 0
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Unless explicitly specified, NDK version will be set to match exactly the required one
|
# Unless explicitly specified, NDK version will be set to match exactly the required one
|
||||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
|
FILAMENT_NDK_VERSION=${GITHUB_NDK_VERSION:-27.0.11718014}
|
||||||
|
|
||||||
|
(! grep "${FILAMENT_NDK_VERSION}" `dirname $0`/../../android/build.gradle > /dev/null) &&
|
||||||
|
echo "Mismatch of NDK versions: want ${FILAMENT_NDK_VERSION} and not found in android/build.gradle" &&
|
||||||
|
exit 1
|
||||||
|
|
||||||
# Install the required NDK version specifically (if not present)
|
# Install the required NDK version specifically (if not present)
|
||||||
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
27.0.11718014
|
|
||||||
@@ -2,5 +2,4 @@
|
|||||||
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
||||||
CONTINUOUS_INTEGRATION=true
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
18
build/common/get-ninja.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
|
OS_NAME=$(uname -s)
|
||||||
|
NINJA_DL_DIR=/tmp/ninja-dl
|
||||||
|
NINJA_PLATFORM=
|
||||||
|
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||||
|
NINJA_PLATFORM=linux
|
||||||
|
elif [[ "$OS_NAME" == "Darwin" ]]; then
|
||||||
|
NINJA_PLATFORM=mac
|
||||||
|
fi
|
||||||
|
curl -L -o /tmp/ninja-dl.zip https://github.com/ninja-build/ninja/releases/download/v${GITHUB_NINJA_VERSION}/ninja-${NINJA_PLATFORM}.zip
|
||||||
|
mkdir -p $NINJA_DL_DIR
|
||||||
|
unzip -q /tmp/ninja-dl.zip -d $NINJA_DL_DIR
|
||||||
|
chmod +x ${NINJA_DL_DIR}/ninja
|
||||||
|
# Install ninja globally for AGP
|
||||||
|
sudo cp ${NINJA_DL_DIR}/ninja /usr/local/bin/
|
||||||
|
fi
|
||||||
6
build/common/versions
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
GITHUB_CLANG_VERSION=14
|
||||||
|
GITHUB_CMAKE_VERSION=3.19.5
|
||||||
|
GITHUB_NINJA_VERSION=1.10.2
|
||||||
|
GITHUB_MESA_VERSION=24.2.1
|
||||||
|
GITHUB_LLVM_VERSION=16
|
||||||
|
GITHUB_NDK_VERSION=27.0.11718014
|
||||||
@@ -28,7 +28,6 @@ set -e
|
|||||||
set -x
|
set -x
|
||||||
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
source `dirname $0`/../common/ci-common.sh
|
||||||
source `dirname $0`/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
@@ -41,4 +40,3 @@ if [[ "${GENERATE_ARCHIVES}" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
./build.sh -i -p ios -c $BUILD_SIMULATOR $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
./build.sh -i -p ios -c $BUILD_SIMULATOR $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
|
||||||
unzip -q ninja-mac.zip
|
|
||||||
chmod +x ninja
|
|
||||||
export PATH="$PWD:$PATH"
|
|
||||||
@@ -32,7 +32,6 @@ set -x
|
|||||||
# $BUILD_DEBUG
|
# $BUILD_DEBUG
|
||||||
# $BUILD_RELEASE
|
# $BUILD_RELEASE
|
||||||
source `dirname $0`/../common/ci-common.sh
|
source `dirname $0`/../common/ci-common.sh
|
||||||
source `dirname $0`/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# version of clang we want to use
|
|
||||||
export GITHUB_CLANG_VERSION=14
|
|
||||||
# version of CMake to use instead of the default one
|
|
||||||
export GITHUB_CMAKE_VERSION=3.19.5
|
|
||||||
# version of ninja to use
|
|
||||||
export GITHUB_NINJA_VERSION=1.10.2
|
|
||||||
|
|
||||||
# Steps for GitHub Workflows
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
|
||||||
# Install ninja
|
|
||||||
wget -q https://github.com/ninja-build/ninja/releases/download/v$GITHUB_NINJA_VERSION/ninja-linux.zip
|
|
||||||
unzip -q ninja-linux.zip
|
|
||||||
export PATH="$PWD:$PATH"
|
|
||||||
|
|
||||||
# Install CMake
|
|
||||||
mkdir -p cmake
|
|
||||||
cd cmake
|
|
||||||
|
|
||||||
sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
|
||||||
sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
|
||||||
sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
|
|
||||||
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
|
||||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
|
||||||
|
|
||||||
# For dawn
|
|
||||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
|
||||||
|
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
|
||||||
fi
|
|
||||||
@@ -28,7 +28,6 @@ set -e
|
|||||||
set -x
|
set -x
|
||||||
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
source `dirname $0`/../common/ci-common.sh
|
||||||
source `dirname $0`/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
|
||||||
unzip -q ninja-mac.zip
|
|
||||||
chmod +x ninja
|
|
||||||
# Install ninja globally for AGP
|
|
||||||
cp ninja /usr/local/bin
|
|
||||||
export PATH="$PWD:$PATH"
|
|
||||||
@@ -31,10 +31,16 @@ set(DIST_ARCH arm64-v8a)
|
|||||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||||
|
|
||||||
|
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
if (NOT FILAMENT_NDK_VERSION)
|
if (NOT FILAMENT_NDK_VERSION)
|
||||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||||
|
if(CMAKE_MATCH_1)
|
||||||
|
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
|
|
||||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||||
list(SORT NDK_VERSIONS)
|
list(SORT NDK_VERSIONS)
|
||||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||||
|
|||||||
@@ -32,10 +32,16 @@ set(DIST_ARCH armeabi-v7a)
|
|||||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||||
|
|
||||||
|
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
if (NOT FILAMENT_NDK_VERSION)
|
if (NOT FILAMENT_NDK_VERSION)
|
||||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||||
|
if(CMAKE_MATCH_1)
|
||||||
|
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
|
|
||||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||||
list(SORT NDK_VERSIONS)
|
list(SORT NDK_VERSIONS)
|
||||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||||
|
|||||||
@@ -31,10 +31,16 @@ set(DIST_ARCH x86)
|
|||||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||||
|
|
||||||
|
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
if (NOT FILAMENT_NDK_VERSION)
|
if (NOT FILAMENT_NDK_VERSION)
|
||||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||||
|
if(CMAKE_MATCH_1)
|
||||||
|
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
|
|
||||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||||
list(SORT NDK_VERSIONS)
|
list(SORT NDK_VERSIONS)
|
||||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||||
|
|||||||
@@ -31,10 +31,16 @@ set(DIST_ARCH x86_64)
|
|||||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||||
|
|
||||||
|
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
if (NOT FILAMENT_NDK_VERSION)
|
if (NOT FILAMENT_NDK_VERSION)
|
||||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||||
|
if(CMAKE_MATCH_1)
|
||||||
|
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||||
|
|
||||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||||
list(SORT NDK_VERSIONS)
|
list(SORT NDK_VERSIONS)
|
||||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||||
|
|||||||
@@ -1,16 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
if [ `uname` == "Linux" ];then
|
|
||||||
source `dirname $0`/../linux/ci-common.sh
|
|
||||||
elif [ `uname` == "Darwin" ];then
|
|
||||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
|
||||||
unzip -q ninja-mac.zip
|
|
||||||
else
|
|
||||||
echo "Unsupported OS"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x ninja
|
|
||||||
export PATH="$PWD:$PATH"
|
|
||||||
|
|
||||||
# Install emscripten.
|
# Install emscripten.
|
||||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.60.zip > emsdk.zip
|
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.60.zip > emsdk.zip
|
||||||
|
|||||||
@@ -259,6 +259,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
|||||||
src/webgpu/WebGPUDriver.h
|
src/webgpu/WebGPUDriver.h
|
||||||
src/webgpu/WebGPUHandles.cpp
|
src/webgpu/WebGPUHandles.cpp
|
||||||
src/webgpu/WebGPUHandles.h
|
src/webgpu/WebGPUHandles.h
|
||||||
|
src/webgpu/WebGPUPipelineCreation.cpp
|
||||||
|
src/webgpu/WebGPUPipelineCreation.h
|
||||||
src/webgpu/WebGPUSwapChain.cpp
|
src/webgpu/WebGPUSwapChain.cpp
|
||||||
src/webgpu/WebGPUSwapChain.h
|
src/webgpu/WebGPUSwapChain.h
|
||||||
src/webgpu/WGPUProgram.cpp
|
src/webgpu/WGPUProgram.cpp
|
||||||
|
|||||||
@@ -66,53 +66,62 @@ namespace {
|
|||||||
};
|
};
|
||||||
wgpu::ShaderModule module = device.CreateShaderModule(&descriptor);
|
wgpu::ShaderModule module = device.CreateShaderModule(&descriptor);
|
||||||
FILAMENT_CHECK_POSTCONDITION(module != nullptr) << "Failed to create " << descriptor.label;
|
FILAMENT_CHECK_POSTCONDITION(module != nullptr) << "Failed to create " << descriptor.label;
|
||||||
module.GetCompilationInfo(wgpu::CallbackMode::AllowSpontaneous,
|
|
||||||
[&descriptor](auto const& status, wgpu::CompilationInfo const* info) {
|
wgpu::Instance instance = device.GetAdapter().GetInstance();
|
||||||
switch (status) {
|
instance.WaitAny(
|
||||||
case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
|
module.GetCompilationInfo(wgpu::CallbackMode::WaitAnyOnly,
|
||||||
FWGPU_LOGW << "Shader compilation info callback cancelled for "
|
[&descriptor](auto const& status,
|
||||||
<< descriptor.label << "?" << utils::io::endl;
|
wgpu::CompilationInfo const* info) {
|
||||||
return;
|
switch (status) {
|
||||||
case wgpu::CompilationInfoRequestStatus::Success:
|
case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
|
||||||
break;
|
FWGPU_LOGW << "Shader compilation info callback cancelled for "
|
||||||
}
|
<< descriptor.label << "?" << utils::io::endl;
|
||||||
if (info != nullptr) {
|
return;
|
||||||
std::stringstream errorStream;
|
case wgpu::CompilationInfoRequestStatus::Success:
|
||||||
int errorCount = 0;
|
|
||||||
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) {
|
|
||||||
wgpu::CompilationMessage const& message = info->messages[msgIndex];
|
|
||||||
switch (message.type) {
|
|
||||||
case wgpu::CompilationMessageType::Info:
|
|
||||||
FWGPU_LOGI << descriptor.label << ": " << message.message
|
|
||||||
<< " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << utils::io::endl;
|
|
||||||
break;
|
|
||||||
case wgpu::CompilationMessageType::Warning:
|
|
||||||
FWGPU_LOGW << "Warning compiling " << descriptor.label << ": "
|
|
||||||
<< message.message << " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << utils::io::endl;
|
|
||||||
break;
|
|
||||||
case wgpu::CompilationMessageType::Error:
|
|
||||||
errorCount++;
|
|
||||||
errorStream << "Error " << errorCount << " : "
|
|
||||||
<< std::string_view(message.message)
|
|
||||||
<< " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << "\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
if (info != nullptr) {
|
||||||
FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
|
std::stringstream errorStream;
|
||||||
<< errorCount << " error(s) compiling " << descriptor.label << ":\n"
|
int errorCount = 0;
|
||||||
<< errorStream.str();
|
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) {
|
||||||
}
|
wgpu::CompilationMessage const& message = info->messages[msgIndex];
|
||||||
FWGPU_LOGD << descriptor.label << " compiled successfully" << utils::io::endl;
|
switch (message.type) {
|
||||||
});
|
case wgpu::CompilationMessageType::Info:
|
||||||
|
FWGPU_LOGI << descriptor.label << ": " << message.message
|
||||||
|
<< " line#:" << message.lineNum
|
||||||
|
<< " linePos:" << message.linePos
|
||||||
|
<< " offset:" << message.offset
|
||||||
|
<< " length:" << message.length
|
||||||
|
<< utils::io::endl;
|
||||||
|
break;
|
||||||
|
case wgpu::CompilationMessageType::Warning:
|
||||||
|
FWGPU_LOGW
|
||||||
|
<< "Warning compiling " << descriptor.label << ": "
|
||||||
|
<< message.message << " line#:" << message.lineNum
|
||||||
|
<< " linePos:" << message.linePos
|
||||||
|
<< " offset:" << message.offset
|
||||||
|
<< " length:" << message.length << utils::io::endl;
|
||||||
|
break;
|
||||||
|
case wgpu::CompilationMessageType::Error:
|
||||||
|
errorCount++;
|
||||||
|
errorStream << "Error " << errorCount << " : "
|
||||||
|
<< std::string_view(message.message)
|
||||||
|
<< " line#:" << message.lineNum
|
||||||
|
<< " linePos:" << message.linePos
|
||||||
|
<< " offset:" << message.offset
|
||||||
|
<< " length:" << message.length << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
|
||||||
|
<< errorCount << " error(s) compiling " << descriptor.label
|
||||||
|
<< ":\n"
|
||||||
|
<< errorStream.str();
|
||||||
|
}
|
||||||
|
FWGPU_LOGD << descriptor.label << " compiled successfully"
|
||||||
|
<< utils::io::endl;
|
||||||
|
}),
|
||||||
|
UINT16_MAX);
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "webgpu/WebGPUDriver.h"
|
#include "webgpu/WebGPUDriver.h"
|
||||||
|
|
||||||
|
#include "WebGPUPipelineCreation.h"
|
||||||
#include "WebGPUSwapChain.h"
|
#include "WebGPUSwapChain.h"
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
#include <backend/platforms/WebGPUPlatform.h>
|
||||||
|
|
||||||
@@ -24,18 +25,20 @@
|
|||||||
#include "private/backend/Dispatcher.h"
|
#include "private/backend/Dispatcher.h"
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
#include <math/mat3.h>
|
#include <math/mat3.h>
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
|
|
||||||
#include <dawn/webgpu_cpp_print.h>
|
#include <dawn/webgpu_cpp_print.h>
|
||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -371,9 +374,7 @@ Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
|||||||
return allocHandle<WGPUTexture>();
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept { return allocHandle<WGPUTexture>(); }
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
||||||
return allocHandle<WGPUProgram>();
|
return allocHandle<WGPUProgram>();
|
||||||
@@ -392,7 +393,7 @@ Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
||||||
@@ -420,7 +421,7 @@ Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
||||||
@@ -432,15 +433,15 @@ Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||||
@@ -494,30 +495,46 @@ void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
|||||||
|
|
||||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||||
TextureUsage usage) {}
|
TextureUsage usage) {
|
||||||
|
constructHandle<WGPUTexture>(th, target, levels, format, samples, w, h, depth, usage, mDevice);
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||||
uint8_t baseLevel, uint8_t levelCount) {}
|
uint8_t baseLevel, uint8_t levelCount) {
|
||||||
|
auto source = handleCast<WGPUTexture>(srch);
|
||||||
|
|
||||||
|
constructHandle<WGPUTexture>(th, source, baseLevel, levelCount);
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||||
backend::TextureSwizzle a) {}
|
backend::TextureSwizzle a) {
|
||||||
|
PANIC_POSTCONDITION("Swizzle WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
Platform::ExternalImageHandleRef externalImage) {}
|
Platform::ExternalImageHandleRef externalImage) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* externalImage) {}
|
void* externalImage) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* image, uint32_t plane) {}
|
void* image, uint32_t plane) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
||||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
||||||
uint32_t depth, TextureUsage usage) {}
|
uint32_t depth, TextureUsage usage) {
|
||||||
|
PANIC_POSTCONDITION("Import WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
||||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
||||||
@@ -594,7 +611,7 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fh) {
|
|||||||
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
||||||
// the GPU supports the given texture format with non-zero optimal tiling features.
|
// the GPU supports the given texture format with non-zero optimal tiling features.
|
||||||
bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
||||||
return true;
|
return WGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebGPUDriver::isTextureSwizzleSupported() {
|
bool WebGPUDriver::isTextureSwizzleSupported() {
|
||||||
@@ -859,6 +876,44 @@ void WebGPUDriver::blit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||||
|
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
|
||||||
|
assert_invariant(program);
|
||||||
|
assert_invariant(program->computeShaderModule == nullptr &&
|
||||||
|
"WebGPU backend does not (yet) support compute pipelines.");
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(program->vertexShaderModule)
|
||||||
|
<< "WebGPU backend requires a vertex shader module for a render pipeline";
|
||||||
|
std::array<wgpu::BindGroupLayout, MAX_DESCRIPTOR_SET_COUNT> bindGroupLayouts{};
|
||||||
|
assert_invariant(bindGroupLayouts.size() >= pipelineState.pipelineLayout.setLayout.size());
|
||||||
|
size_t bindGroupLayoutCount = 0;
|
||||||
|
for (size_t i = 0; i < bindGroupLayouts.size(); i++) {
|
||||||
|
const auto handle = pipelineState.pipelineLayout.setLayout[bindGroupLayoutCount];
|
||||||
|
if (handle.getId() == HandleBase::nullid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bindGroupLayouts[bindGroupLayoutCount++] =
|
||||||
|
handleCast<WebGPUDescriptorSetLayout>(handle)->getLayout();
|
||||||
|
}
|
||||||
|
std::stringstream layoutLabelStream;
|
||||||
|
layoutLabelStream << program->name.c_str() << " layout";
|
||||||
|
const auto layoutLabel = layoutLabelStream.str();
|
||||||
|
const wgpu::PipelineLayoutDescriptor layoutDescriptor{
|
||||||
|
.label = wgpu::StringView(layoutLabel),
|
||||||
|
.bindGroupLayoutCount = bindGroupLayoutCount,
|
||||||
|
.bindGroupLayouts = bindGroupLayouts.data()
|
||||||
|
// TODO investigate immediateDataRangeByteSize
|
||||||
|
};
|
||||||
|
const wgpu::PipelineLayout layout = mDevice.CreatePipelineLayout(&layoutDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(layout)
|
||||||
|
<< "Failed to create wgpu::PipelineLayout for render pipeline for "
|
||||||
|
<< layoutDescriptor.label;
|
||||||
|
auto const* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(pipelineState.vertexBufferInfo);
|
||||||
|
assert_invariant(vertexBufferInfo);
|
||||||
|
const wgpu::RenderPipeline pipeline = createWebGPURenderPipeline(mDevice, *program,
|
||||||
|
*vertexBufferInfo, layout, pipelineState.rasterState, pipelineState.stencilState,
|
||||||
|
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
||||||
|
mSwapChain->getDepthFormat());
|
||||||
|
// TODO: uncomment once we have a valid pipeline to set
|
||||||
|
// mRenderPassEncoder.SetPipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||||
|
|||||||
@@ -294,4 +294,362 @@ void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
|||||||
// layout index for efficiency. Add guards if wrong.
|
// layout index for efficiency. Add guards if wrong.
|
||||||
entries[index] = std::move(entry);
|
entries[index] = std::move(entry);
|
||||||
}
|
}
|
||||||
|
// From createTextureR
|
||||||
|
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
|
wgpu::Device device) noexcept {
|
||||||
|
|
||||||
|
// First the texture aspect
|
||||||
|
wgpu::TextureDescriptor desc;
|
||||||
|
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
// Should be safe to assume external is 2d
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL: {
|
||||||
|
desc.dimension = wgpu::TextureDimension::e2D;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerType::SAMPLER_3D: {
|
||||||
|
desc.dimension = wgpu::TextureDimension::e3D;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desc.size = { .width = width, .height = height, .depthOrArrayLayers = depth };
|
||||||
|
desc.format = fToWGPUTextureFormat(format);
|
||||||
|
assert_invariant(desc.format != wgpu::TextureFormat::Undefined);
|
||||||
|
|
||||||
|
// WGPU requires this to be true. Filament should comply
|
||||||
|
assert(samples == 1 || samples || 4);
|
||||||
|
|
||||||
|
desc.sampleCount = samples;
|
||||||
|
desc.usage = fToWGPUTextureUsage(usage);
|
||||||
|
desc.mipLevelCount = levels;
|
||||||
|
|
||||||
|
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from Filament
|
||||||
|
desc.viewFormats = nullptr;
|
||||||
|
|
||||||
|
texture = device.CreateTexture(&desc);
|
||||||
|
|
||||||
|
// TODO should a default levelCount be something other than 0? Sample count?
|
||||||
|
texView = makeTextureView(0, 1);
|
||||||
|
}
|
||||||
|
// From createTextureViewR
|
||||||
|
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||||
|
texture = src->texture;
|
||||||
|
texView = makeTextureView(baseLevel, levelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
|
||||||
|
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
||||||
|
|
||||||
|
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
||||||
|
// TODO Validate assumptions, revisit if issues.
|
||||||
|
if (any(TextureUsage::BLIT_SRC & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::CopySrc;
|
||||||
|
}
|
||||||
|
if (any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::CopyDst;
|
||||||
|
}
|
||||||
|
if (any(TextureUsage::SAMPLEABLE & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::TextureBinding;
|
||||||
|
}
|
||||||
|
// WGPU Render attachment covers either color or stencil situation dependant
|
||||||
|
// NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
|
||||||
|
// issues, investigate here.
|
||||||
|
if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
|
||||||
|
TextureUsage::DEPTH_ATTACHMENT) &
|
||||||
|
fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::RenderAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is from Vulkan logic- if there are any issues try disabling this first, allows perf
|
||||||
|
// benefit though
|
||||||
|
const bool useTransientAttachment =
|
||||||
|
// Usage consists of attachment flags only.
|
||||||
|
none(fUsage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
|
// Usage contains at least one attachment flag.
|
||||||
|
any(fUsage & TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
|
// Depth resolve cannot use transient attachment because it uses a custom shader.
|
||||||
|
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
|
||||||
|
// restriction.
|
||||||
|
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
|
||||||
|
// and above to be able to support stencil resolve (along with depth).
|
||||||
|
!(any(fUsage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
|
||||||
|
if (useTransientAttachment) {
|
||||||
|
retUsage |= wgpu::TextureUsage::TransientAttachment;
|
||||||
|
}
|
||||||
|
// NOTE: Unused wgpu flags:
|
||||||
|
// StorageBinding
|
||||||
|
// StorageAttachment
|
||||||
|
|
||||||
|
// NOTE: Unused Filament flags:
|
||||||
|
// SUBPASS_INPUT VK goes to input attachment which we don't support right now
|
||||||
|
// PROTECTED
|
||||||
|
return retUsage;
|
||||||
|
}
|
||||||
|
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
|
||||||
|
switch (fUsage) {
|
||||||
|
case filament::backend::TextureFormat::R8:
|
||||||
|
return wgpu::TextureFormat::R8Unorm;
|
||||||
|
case filament::backend::TextureFormat::R8_SNORM:
|
||||||
|
return wgpu::TextureFormat::R8Snorm;
|
||||||
|
case filament::backend::TextureFormat::R8UI:
|
||||||
|
return wgpu::TextureFormat::R8Uint;
|
||||||
|
case filament::backend::TextureFormat::R8I:
|
||||||
|
return wgpu::TextureFormat::R8Sint;
|
||||||
|
case filament::backend::TextureFormat::STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Stencil8;
|
||||||
|
case filament::backend::TextureFormat::R16F:
|
||||||
|
return wgpu::TextureFormat::R16Float;
|
||||||
|
case filament::backend::TextureFormat::R16UI:
|
||||||
|
return wgpu::TextureFormat::R16Uint;
|
||||||
|
case filament::backend::TextureFormat::R16I:
|
||||||
|
return wgpu::TextureFormat::R16Sint;
|
||||||
|
case filament::backend::TextureFormat::RG8:
|
||||||
|
return wgpu::TextureFormat::RG8Unorm;
|
||||||
|
case filament::backend::TextureFormat::RG8_SNORM:
|
||||||
|
return wgpu::TextureFormat::RG8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RG8UI:
|
||||||
|
return wgpu::TextureFormat::RG8Uint;
|
||||||
|
case filament::backend::TextureFormat::RG8I:
|
||||||
|
return wgpu::TextureFormat::RG8Sint;
|
||||||
|
case filament::backend::TextureFormat::R32F:
|
||||||
|
return wgpu::TextureFormat::R32Float;
|
||||||
|
case filament::backend::TextureFormat::R32UI:
|
||||||
|
return wgpu::TextureFormat::R32Uint;
|
||||||
|
case filament::backend::TextureFormat::R32I:
|
||||||
|
return wgpu::TextureFormat::R32Sint;
|
||||||
|
case filament::backend::TextureFormat::RG16F:
|
||||||
|
return wgpu::TextureFormat::RG16Float;
|
||||||
|
case filament::backend::TextureFormat::RG16UI:
|
||||||
|
return wgpu::TextureFormat::RG16Uint;
|
||||||
|
case filament::backend::TextureFormat::RG16I:
|
||||||
|
return wgpu::TextureFormat::RG16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA8:
|
||||||
|
return wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_A8:
|
||||||
|
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA8_SNORM:
|
||||||
|
return wgpu::TextureFormat::RGBA8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RGBA8UI:
|
||||||
|
return wgpu::TextureFormat::RGBA8Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA8I:
|
||||||
|
return wgpu::TextureFormat::RGBA8Sint;
|
||||||
|
case filament::backend::TextureFormat::DEPTH16:
|
||||||
|
return wgpu::TextureFormat::Depth16Unorm;
|
||||||
|
case filament::backend::TextureFormat::DEPTH24:
|
||||||
|
return wgpu::TextureFormat::Depth24Plus;
|
||||||
|
case filament::backend::TextureFormat::DEPTH32F:
|
||||||
|
return wgpu::TextureFormat::Depth32Float;
|
||||||
|
case filament::backend::TextureFormat::DEPTH24_STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Depth24PlusStencil8;
|
||||||
|
case filament::backend::TextureFormat::DEPTH32F_STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Depth32FloatStencil8;
|
||||||
|
case filament::backend::TextureFormat::RG32F:
|
||||||
|
return wgpu::TextureFormat::RG32Float;
|
||||||
|
case filament::backend::TextureFormat::RG32UI:
|
||||||
|
return wgpu::TextureFormat::RG32Uint;
|
||||||
|
case filament::backend::TextureFormat::RG32I:
|
||||||
|
return wgpu::TextureFormat::RG32Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA16F:
|
||||||
|
return wgpu::TextureFormat::RGBA16Float;
|
||||||
|
case filament::backend::TextureFormat::RGBA16UI:
|
||||||
|
return wgpu::TextureFormat::RGBA16Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA16I:
|
||||||
|
return wgpu::TextureFormat::RGBA16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA32F:
|
||||||
|
return wgpu::TextureFormat::RGBA32Float;
|
||||||
|
case filament::backend::TextureFormat::RGBA32UI:
|
||||||
|
return wgpu::TextureFormat::RGBA32Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA32I:
|
||||||
|
return wgpu::TextureFormat::RGBA32Sint;
|
||||||
|
case filament::backend::TextureFormat::EAC_R11:
|
||||||
|
return wgpu::TextureFormat::EACR11Unorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_R11_SIGNED:
|
||||||
|
return wgpu::TextureFormat::EACR11Snorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_RG11:
|
||||||
|
return wgpu::TextureFormat::EACRG11Unorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_RG11_SIGNED:
|
||||||
|
return wgpu::TextureFormat::EACRG11Snorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_RGB8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_SRGB8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::ETC2_RGB8_A1:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8A1Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_SRGB8_A1:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::ETC2_EAC_RGBA8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_EAC_SRGBA8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_4x4:
|
||||||
|
return wgpu::TextureFormat::ASTC4x4Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||||
|
return wgpu::TextureFormat::ASTC4x4UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_5x4:
|
||||||
|
return wgpu::TextureFormat::ASTC5x4Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||||
|
return wgpu::TextureFormat::ASTC5x4UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_5x5:
|
||||||
|
return wgpu::TextureFormat::ASTC5x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||||
|
return wgpu::TextureFormat::ASTC5x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_6x5:
|
||||||
|
return wgpu::TextureFormat::ASTC6x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||||
|
return wgpu::TextureFormat::ASTC6x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_6x6:
|
||||||
|
return wgpu::TextureFormat::ASTC6x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||||
|
return wgpu::TextureFormat::ASTC6x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x5:
|
||||||
|
return wgpu::TextureFormat::ASTC8x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||||
|
return wgpu::TextureFormat::ASTC8x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x6:
|
||||||
|
return wgpu::TextureFormat::ASTC8x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||||
|
return wgpu::TextureFormat::ASTC8x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x8:
|
||||||
|
return wgpu::TextureFormat::ASTC8x8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||||
|
return wgpu::TextureFormat::ASTC8x8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x5:
|
||||||
|
return wgpu::TextureFormat::ASTC10x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||||
|
return wgpu::TextureFormat::ASTC10x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x6:
|
||||||
|
return wgpu::TextureFormat::ASTC10x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||||
|
return wgpu::TextureFormat::ASTC10x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x8:
|
||||||
|
return wgpu::TextureFormat::ASTC10x8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||||
|
return wgpu::TextureFormat::ASTC10x8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x10:
|
||||||
|
return wgpu::TextureFormat::ASTC10x10Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||||
|
return wgpu::TextureFormat::ASTC10x10UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_12x10:
|
||||||
|
return wgpu::TextureFormat::ASTC12x10Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||||
|
return wgpu::TextureFormat::ASTC12x10UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_12x12:
|
||||||
|
return wgpu::TextureFormat::ASTC12x12Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||||
|
return wgpu::TextureFormat::ASTC12x12UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RED_RGTC1:
|
||||||
|
return wgpu::TextureFormat::BC4RUnorm;
|
||||||
|
case filament::backend::TextureFormat::SIGNED_RED_RGTC1:
|
||||||
|
return wgpu::TextureFormat::BC4RSnorm;
|
||||||
|
case filament::backend::TextureFormat::RED_GREEN_RGTC2:
|
||||||
|
return wgpu::TextureFormat::BC5RGUnorm;
|
||||||
|
case filament::backend::TextureFormat::SIGNED_RED_GREEN_RGTC2:
|
||||||
|
return wgpu::TextureFormat::BC5RGSnorm;
|
||||||
|
case filament::backend::TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
|
return wgpu::TextureFormat::BC6HRGBUfloat;
|
||||||
|
case filament::backend::TextureFormat::RGB_BPTC_SIGNED_FLOAT:
|
||||||
|
return wgpu::TextureFormat::BC6HRGBFloat;
|
||||||
|
case filament::backend::TextureFormat::RGBA_BPTC_UNORM:
|
||||||
|
return wgpu::TextureFormat::BC7RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
return wgpu::TextureFormat::BC7RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGB565:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and discard the alpha and lower precision.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB9_E5:
|
||||||
|
return wgpu::TextureFormat::RGB9E5Ufloat;
|
||||||
|
case filament::backend::TextureFormat::RGB5_A1:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and handle the packing/unpacking in shaders.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGBA4:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and handle the packing/unpacking in shaders.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB8:
|
||||||
|
// No direct sRGB equivalent in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8:
|
||||||
|
// No direct sRGB equivalent in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGB8_SNORM:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RGB8UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB8I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Sint;
|
||||||
|
case filament::backend::TextureFormat::R11F_G11F_B10F:
|
||||||
|
return wgpu::TextureFormat::RG11B10Ufloat;
|
||||||
|
case filament::backend::TextureFormat::UNUSED:
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB10_A2:
|
||||||
|
return wgpu::TextureFormat::RGB10A2Unorm;
|
||||||
|
case filament::backend::TextureFormat::RGB16F:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Float;
|
||||||
|
case filament::backend::TextureFormat::RGB16UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB16I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGB32F:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Float;
|
||||||
|
case filament::backend::TextureFormat::RGB32UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB32I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Sint;
|
||||||
|
case filament::backend::TextureFormat::DXT1_RGB:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT1_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT3_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC2RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT5_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC3RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT1_SRGB:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT1_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT3_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC2RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT5_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC3RGBAUnormSrgb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel,
|
||||||
|
const uint8_t& levelCount) {
|
||||||
|
wgpu::TextureViewDescriptor desc;
|
||||||
|
desc.baseMipLevel = baseLevel;
|
||||||
|
desc.mipLevelCount = levelCount;
|
||||||
|
|
||||||
|
// baseArrayLayer is required, making a guess
|
||||||
|
desc.baseArrayLayer = 0;
|
||||||
|
// Have not found an analouge to aspect in other drivers, but ALL should be unrestrictive.
|
||||||
|
// TODO Can we make this better?
|
||||||
|
desc.aspect = wgpu::TextureAspect::All;
|
||||||
|
|
||||||
|
// The rest of the properties should be fine to leave as default, using the texture params.
|
||||||
|
desc.label = "TODO";
|
||||||
|
|
||||||
|
desc.format = wgpu::TextureFormat::Undefined;
|
||||||
|
desc.dimension = wgpu::TextureViewDimension::Undefined;
|
||||||
|
desc.usage = wgpu::TextureUsage::None;
|
||||||
|
|
||||||
|
return texture.CreateView(&desc);
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -132,21 +132,32 @@ private:
|
|||||||
wgpu::BindGroup mBindGroup;
|
wgpu::BindGroup mBindGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
class WGPUTexture : public HwTexture {
|
||||||
// Update the struct when used by WebGPU driver.
|
public:
|
||||||
struct WGPUTexture : public HwTexture {
|
|
||||||
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) noexcept;
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
|
wgpu::Device device) noexcept;
|
||||||
|
|
||||||
// constructors for creating texture views
|
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||||
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
|
||||||
|
|
||||||
|
const wgpu::Texture& getTexture() const { return texture; }
|
||||||
|
const wgpu::Sampler& getSampler() const { return sampler; }
|
||||||
|
const wgpu::TextureView& getTexView() const { return texView; }
|
||||||
|
|
||||||
|
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount);
|
||||||
|
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
|
||||||
|
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
|
||||||
|
// ref counted pointer) when making views. View is optional
|
||||||
wgpu::Texture texture = nullptr;
|
wgpu::Texture texture = nullptr;
|
||||||
// TODO: Adding this but not yet setting it up. Filament "Textures" are combined image samplers,
|
// TODO: Adding this but not yet setting it up. Filament "Textures" are combined image samplers,
|
||||||
// rep both.
|
// rep both.
|
||||||
wgpu::Sampler sampler = nullptr;
|
wgpu::Sampler sampler = nullptr;
|
||||||
//TODO: Not sure all the ways HwTexture is used. Overloading like this might be entirely wrong.
|
// TODO: Not sure all the ways HwTexture is used. Overloading like this might be entirely wrong.
|
||||||
wgpu::TextureView texView = nullptr;
|
wgpu::TextureView texView = nullptr;
|
||||||
|
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||||
@@ -170,7 +181,7 @@ struct WGPURenderTarget : public HwRenderTarget {
|
|||||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
||||||
: level(level),
|
: level(level),
|
||||||
layer(layer),
|
layer(layer),
|
||||||
texture(gpuTexture->texture),
|
texture(gpuTexture->getTexture()),
|
||||||
mWGPUTexture(gpuTexture) {}
|
mWGPUTexture(gpuTexture) {}
|
||||||
|
|
||||||
uint8_t level = 0;
|
uint8_t level = 0;
|
||||||
|
|||||||
254
filament/backend/src/webgpu/WebGPUPipelineCreation.cpp
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "WebGPUPipelineCreation.h"
|
||||||
|
|
||||||
|
#include "WebGPUHandles.h"
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
#include <utils/debug.h>
|
||||||
|
|
||||||
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr wgpu::PrimitiveTopology toWebGPU(PrimitiveType primitiveType) {
|
||||||
|
switch (primitiveType) {
|
||||||
|
case PrimitiveType::POINTS:
|
||||||
|
return wgpu::PrimitiveTopology::PointList;
|
||||||
|
case PrimitiveType::LINES:
|
||||||
|
return wgpu::PrimitiveTopology::LineList;
|
||||||
|
case PrimitiveType::LINE_STRIP:
|
||||||
|
return wgpu::PrimitiveTopology::LineStrip;
|
||||||
|
case PrimitiveType::TRIANGLES:
|
||||||
|
return wgpu::PrimitiveTopology::TriangleList;
|
||||||
|
case PrimitiveType::TRIANGLE_STRIP:
|
||||||
|
return wgpu::PrimitiveTopology::TriangleStrip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::CullMode toWebGPU(CullingMode cullMode) {
|
||||||
|
switch (cullMode) {
|
||||||
|
case CullingMode::NONE:
|
||||||
|
return wgpu::CullMode::None;
|
||||||
|
case CullingMode::FRONT:
|
||||||
|
return wgpu::CullMode::Front;
|
||||||
|
case CullingMode::BACK:
|
||||||
|
return wgpu::CullMode::Back;
|
||||||
|
case CullingMode::FRONT_AND_BACK:
|
||||||
|
// no WegGPU equivalent of front and back
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(false)
|
||||||
|
<< "WebGPU does not support CullingMode::FRONT_AND_BACK";
|
||||||
|
return wgpu::CullMode::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::CompareFunction toWebGPU(SamplerCompareFunc compareFunction) {
|
||||||
|
switch (compareFunction) {
|
||||||
|
case SamplerCompareFunc::LE:
|
||||||
|
return wgpu::CompareFunction::LessEqual;
|
||||||
|
case SamplerCompareFunc::GE:
|
||||||
|
return wgpu::CompareFunction::GreaterEqual;
|
||||||
|
case SamplerCompareFunc::L:
|
||||||
|
return wgpu::CompareFunction::Less;
|
||||||
|
case SamplerCompareFunc::G:
|
||||||
|
return wgpu::CompareFunction::Greater;
|
||||||
|
case SamplerCompareFunc::E:
|
||||||
|
return wgpu::CompareFunction::Equal;
|
||||||
|
case SamplerCompareFunc::NE:
|
||||||
|
return wgpu::CompareFunction::NotEqual;
|
||||||
|
case SamplerCompareFunc::A:
|
||||||
|
return wgpu::CompareFunction::Always;
|
||||||
|
case SamplerCompareFunc::N:
|
||||||
|
return wgpu::CompareFunction::Never;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::StencilOperation toWebGPU(StencilOperation stencilOp) {
|
||||||
|
switch (stencilOp) {
|
||||||
|
case StencilOperation::KEEP:
|
||||||
|
return wgpu::StencilOperation::Keep;
|
||||||
|
case StencilOperation::ZERO:
|
||||||
|
return wgpu::StencilOperation::Zero;
|
||||||
|
case StencilOperation::REPLACE:
|
||||||
|
return wgpu::StencilOperation::Replace;
|
||||||
|
case StencilOperation::INCR:
|
||||||
|
return wgpu::StencilOperation::IncrementClamp;
|
||||||
|
case StencilOperation::INCR_WRAP:
|
||||||
|
return wgpu::StencilOperation::IncrementWrap;
|
||||||
|
case StencilOperation::DECR:
|
||||||
|
return wgpu::StencilOperation::DecrementClamp;
|
||||||
|
case StencilOperation::DECR_WRAP:
|
||||||
|
return wgpu::StencilOperation::DecrementWrap;
|
||||||
|
case StencilOperation::INVERT:
|
||||||
|
return wgpu::StencilOperation::Invert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::BlendOperation toWebGPU(BlendEquation blendOp) {
|
||||||
|
switch (blendOp) {
|
||||||
|
case BlendEquation::ADD:
|
||||||
|
return wgpu::BlendOperation::Add;
|
||||||
|
case BlendEquation::SUBTRACT:
|
||||||
|
return wgpu::BlendOperation::Subtract;
|
||||||
|
case BlendEquation::REVERSE_SUBTRACT:
|
||||||
|
return wgpu::BlendOperation::ReverseSubtract;
|
||||||
|
case BlendEquation::MIN:
|
||||||
|
return wgpu::BlendOperation::Min;
|
||||||
|
case BlendEquation::MAX:
|
||||||
|
return wgpu::BlendOperation::Max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::BlendFactor toWebGPU(BlendFunction blendFunction) {
|
||||||
|
switch (blendFunction) {
|
||||||
|
case BlendFunction::ZERO:
|
||||||
|
return wgpu::BlendFactor::Zero;
|
||||||
|
case BlendFunction::ONE:
|
||||||
|
return wgpu::BlendFactor::One;
|
||||||
|
case BlendFunction::SRC_COLOR:
|
||||||
|
return wgpu::BlendFactor::Src;
|
||||||
|
case BlendFunction::ONE_MINUS_SRC_COLOR:
|
||||||
|
return wgpu::BlendFactor::OneMinusSrc;
|
||||||
|
case BlendFunction::DST_COLOR:
|
||||||
|
return wgpu::BlendFactor::Dst;
|
||||||
|
case BlendFunction::ONE_MINUS_DST_COLOR:
|
||||||
|
return wgpu::BlendFactor::OneMinusDst;
|
||||||
|
case BlendFunction::SRC_ALPHA:
|
||||||
|
return wgpu::BlendFactor::SrcAlpha;
|
||||||
|
case BlendFunction::ONE_MINUS_SRC_ALPHA:
|
||||||
|
return wgpu::BlendFactor::OneMinusSrcAlpha;
|
||||||
|
case BlendFunction::DST_ALPHA:
|
||||||
|
return wgpu::BlendFactor::DstAlpha;
|
||||||
|
case BlendFunction::ONE_MINUS_DST_ALPHA:
|
||||||
|
return wgpu::BlendFactor::OneMinusDstAlpha;
|
||||||
|
case BlendFunction::SRC_ALPHA_SATURATE:
|
||||||
|
return wgpu::BlendFactor::SrcAlphaSaturated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
|
||||||
|
WGPUProgram const& program, WGPUVertexBufferInfo const& vertexBufferInfo,
|
||||||
|
wgpu::PipelineLayout const& layout, RasterState const& rasterState,
|
||||||
|
StencilState const& stencilState, PolygonOffset const& polygonOffset,
|
||||||
|
PrimitiveType primitiveType, wgpu::TextureFormat colorFormat,
|
||||||
|
wgpu::TextureFormat depthFormat) {
|
||||||
|
assert_invariant(program.vertexShaderModule);
|
||||||
|
const wgpu::DepthStencilState depthStencilState {
|
||||||
|
.format = depthFormat,
|
||||||
|
.depthWriteEnabled = rasterState.depthWrite,
|
||||||
|
.depthCompare = toWebGPU(rasterState.depthFunc),
|
||||||
|
.stencilFront = {
|
||||||
|
.compare = toWebGPU(stencilState.front.stencilFunc),
|
||||||
|
.failOp = toWebGPU(stencilState.front.stencilOpStencilFail),
|
||||||
|
.depthFailOp = toWebGPU(stencilState.front.stencilOpDepthFail),
|
||||||
|
.passOp = toWebGPU(stencilState.front.stencilOpDepthStencilPass),
|
||||||
|
},
|
||||||
|
.stencilBack = {
|
||||||
|
.compare = toWebGPU(stencilState.back.stencilFunc),
|
||||||
|
.failOp = toWebGPU(stencilState.back.stencilOpStencilFail),
|
||||||
|
.depthFailOp = toWebGPU(stencilState.back.stencilOpDepthFail),
|
||||||
|
.passOp = toWebGPU(stencilState.back.stencilOpDepthStencilPass),
|
||||||
|
},
|
||||||
|
.stencilReadMask = 0,
|
||||||
|
.stencilWriteMask = stencilState.stencilWrite ? 0xFFFFFFFF : 0,
|
||||||
|
.depthBias = static_cast<int32_t>(polygonOffset.constant),
|
||||||
|
.depthBiasSlopeScale = polygonOffset.slope,
|
||||||
|
.depthBiasClamp = 0.0f
|
||||||
|
};
|
||||||
|
std::stringstream pipelineLabelStream;
|
||||||
|
pipelineLabelStream << program.name.c_str() << " pipeline";
|
||||||
|
const auto pipelineLabel = pipelineLabelStream.str();
|
||||||
|
wgpu::RenderPipelineDescriptor pipelineDescriptor{
|
||||||
|
.label = wgpu::StringView(pipelineLabel),
|
||||||
|
.layout = layout,
|
||||||
|
.vertex = {
|
||||||
|
.module = program.vertexShaderModule,
|
||||||
|
.entryPoint = "main",
|
||||||
|
.constantCount = program.constants.size(),
|
||||||
|
.constants = program.constants.data(),
|
||||||
|
.bufferCount = vertexBufferInfo.getVertexBufferLayoutSize(),
|
||||||
|
.buffers = vertexBufferInfo.getVertexBufferLayout()
|
||||||
|
},
|
||||||
|
.primitive = {
|
||||||
|
.topology = toWebGPU(primitiveType),
|
||||||
|
// TODO should we assume some constant format here or is there a way to get
|
||||||
|
// this from PipelineState somehow or elsewhere?
|
||||||
|
// Perhaps, cache/assert format from index buffers as they are requested?
|
||||||
|
.stripIndexFormat = wgpu::IndexFormat::Undefined,
|
||||||
|
.frontFace = rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
|
||||||
|
.cullMode = toWebGPU(rasterState.culling),
|
||||||
|
// TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
|
||||||
|
// starting there
|
||||||
|
.unclippedDepth = !rasterState.depthClamp &&
|
||||||
|
device.HasFeature(wgpu::FeatureName::DepthClipControl)
|
||||||
|
},
|
||||||
|
.depthStencil = &depthStencilState,
|
||||||
|
.multisample = {
|
||||||
|
.count = 1, // TODO need to get this from the render target
|
||||||
|
.mask = 0xFFFFFFFF,
|
||||||
|
.alphaToCoverageEnabled = rasterState.alphaToCoverage
|
||||||
|
},
|
||||||
|
.fragment = nullptr // will add below if fragment module is included
|
||||||
|
};
|
||||||
|
wgpu::FragmentState fragmentState = {};
|
||||||
|
std::array<wgpu::ColorTargetState, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> colorTargets {};
|
||||||
|
const wgpu::BlendState blendState {
|
||||||
|
.color = {
|
||||||
|
.operation = toWebGPU(rasterState.blendEquationRGB),
|
||||||
|
.srcFactor = toWebGPU(rasterState.blendFunctionSrcRGB),
|
||||||
|
.dstFactor = toWebGPU(rasterState.blendFunctionDstRGB)
|
||||||
|
},
|
||||||
|
.alpha = {
|
||||||
|
.operation = toWebGPU(rasterState.blendEquationAlpha),
|
||||||
|
.srcFactor = toWebGPU(rasterState.blendFunctionSrcAlpha),
|
||||||
|
.dstFactor = toWebGPU(rasterState.blendFunctionDstAlpha)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (program.fragmentShaderModule != nullptr) {
|
||||||
|
fragmentState.module = program.fragmentShaderModule;
|
||||||
|
fragmentState.entryPoint = "main";
|
||||||
|
fragmentState.constantCount = program.constants.size(),
|
||||||
|
fragmentState.constants = program.constants.data(),
|
||||||
|
fragmentState.targetCount = 1; // TODO need to get this from the render target
|
||||||
|
assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||||
|
for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) {
|
||||||
|
auto& colorTarget = colorTargets[targetIndex];
|
||||||
|
colorTarget.format = colorFormat;
|
||||||
|
colorTarget.blend = rasterState.hasBlending() ? &blendState : nullptr;
|
||||||
|
colorTarget.writeMask =
|
||||||
|
rasterState.colorWrite ? wgpu::ColorWriteMask::All : wgpu::ColorWriteMask::None;
|
||||||
|
}
|
||||||
|
pipelineDescriptor.fragment = &fragmentState;
|
||||||
|
}
|
||||||
|
const wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(pipeline)
|
||||||
|
<< "Failed to create render pipeline for " << pipelineDescriptor.label;
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace filament::backend
|
||||||
46
filament/backend/src/webgpu/WebGPUPipelineCreation.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace wgpu {
|
||||||
|
class Device;
|
||||||
|
class PipelineLayout;
|
||||||
|
class RenderPipeline;
|
||||||
|
enum class TextureFormat : uint32_t;
|
||||||
|
}// namespace wgpu
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
struct PolygonOffset;
|
||||||
|
enum class PrimitiveType : uint8_t;
|
||||||
|
struct RasterState;
|
||||||
|
struct StencilState;
|
||||||
|
|
||||||
|
class WGPUVertexBufferInfo;
|
||||||
|
class WGPUProgram;
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const&,
|
||||||
|
WGPUProgram const&, WGPUVertexBufferInfo const&, wgpu::PipelineLayout const&,
|
||||||
|
RasterState const&, StencilState const&, PolygonOffset const&, PrimitiveType,
|
||||||
|
wgpu::TextureFormat colorFormat, wgpu::TextureFormat depthFormat);
|
||||||
|
|
||||||
|
}// namespace filament::backend
|
||||||
|
|
||||||
|
#endif// TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||||
@@ -73,7 +73,8 @@ void printSurfaceCapabilitiesDetails(wgpu::SurfaceCapabilities const& capabiliti
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config,
|
||||||
|
wgpu::TextureFormat depthFormat) {
|
||||||
std::stringstream formatStream{};
|
std::stringstream formatStream{};
|
||||||
formatStream << config.format;
|
formatStream << config.format;
|
||||||
std::stringstream usageStream{};
|
std::stringstream usageStream{};
|
||||||
@@ -82,6 +83,8 @@ void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
|||||||
alphaModeStream << config.alphaMode;
|
alphaModeStream << config.alphaMode;
|
||||||
std::stringstream presentModeStream{};
|
std::stringstream presentModeStream{};
|
||||||
presentModeStream << config.presentMode;
|
presentModeStream << config.presentMode;
|
||||||
|
std::stringstream depthFormatStream;
|
||||||
|
depthFormatStream << depthFormat;
|
||||||
FWGPU_LOGI << "WebGPU surface configuration:" << utils::io::endl;
|
FWGPU_LOGI << "WebGPU surface configuration:" << utils::io::endl;
|
||||||
FWGPU_LOGI << " surface format: " << formatStream.str() << utils::io::endl;
|
FWGPU_LOGI << " surface format: " << formatStream.str() << utils::io::endl;
|
||||||
FWGPU_LOGI << " surface usage: " << usageStream.str() << utils::io::endl;
|
FWGPU_LOGI << " surface usage: " << usageStream.str() << utils::io::endl;
|
||||||
@@ -98,10 +101,11 @@ void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
|||||||
FWGPU_LOGI << " surface width: " << config.width << utils::io::endl;
|
FWGPU_LOGI << " surface width: " << config.width << utils::io::endl;
|
||||||
FWGPU_LOGI << " surface height: " << config.height << utils::io::endl;
|
FWGPU_LOGI << " surface height: " << config.height << utils::io::endl;
|
||||||
FWGPU_LOGI << " surface present mode: " << presentModeStream.str() << utils::io::endl;
|
FWGPU_LOGI << " surface present mode: " << presentModeStream.str() << utils::io::endl;
|
||||||
|
FWGPU_LOGI << "WebGPU selected depth format: " << depthFormatStream.str() << utils::io::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
constexpr wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
||||||
wgpu::TextureFormat const* availableFormats, bool useSRGBColorSpace) {
|
wgpu::TextureFormat const* availableFormats, bool useSRGBColorSpace) {
|
||||||
const std::array expectedColorFormats =
|
const std::array expectedColorFormats =
|
||||||
useSRGBColorSpace ?
|
useSRGBColorSpace ?
|
||||||
@@ -119,7 +123,21 @@ wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
|||||||
return *firstFoundColorFormat;
|
return *firstFoundColorFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
constexpr wgpu::TextureFormat selectDepthFormat(bool depth32FloatStencil8Enabled,
|
||||||
|
bool needStencil) {
|
||||||
|
if (needStencil) {
|
||||||
|
if (depth32FloatStencil8Enabled) {
|
||||||
|
return wgpu::TextureFormat::Depth32FloatStencil8;
|
||||||
|
} else {
|
||||||
|
return wgpu::TextureFormat::Depth24PlusStencil8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// other options: Depth16Unorm or Depth24Plus
|
||||||
|
return wgpu::TextureFormat::Depth32Float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
||||||
wgpu::PresentMode const* availablePresentModes) {
|
wgpu::PresentMode const* availablePresentModes) {
|
||||||
// Verify that our chosen present mode is supported. In practice all devices support the FIFO
|
// Verify that our chosen present mode is supported. In practice all devices support the FIFO
|
||||||
// mode, but we check for it anyway for completeness. (and to avoid validation warnings)
|
// mode, but we check for it anyway for completeness. (and to avoid validation warnings)
|
||||||
@@ -133,7 +151,7 @@ wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
|||||||
return desiredPresentMode;
|
return desiredPresentMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
constexpr wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
||||||
wgpu::CompositeAlphaMode const* availableAlphaModes) {
|
wgpu::CompositeAlphaMode const* availableAlphaModes) {
|
||||||
bool autoAvailable = false;
|
bool autoAvailable = false;
|
||||||
bool inheritAvailable = false;
|
bool inheritAvailable = false;
|
||||||
@@ -209,7 +227,7 @@ void initConfig(wgpu::SurfaceConfiguration& config, wgpu::Device const& device,
|
|||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
||||||
wgpu::Adapter& adapter, wgpu::Device& device, uint64_t flags)
|
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags)
|
||||||
: mSurface(surface) {
|
: mSurface(surface) {
|
||||||
wgpu::SurfaceCapabilities capabilities = {};
|
wgpu::SurfaceCapabilities capabilities = {};
|
||||||
if (!mSurface.GetCapabilities(adapter, &capabilities)) {
|
if (!mSurface.GetCapabilities(adapter, &capabilities)) {
|
||||||
@@ -220,7 +238,13 @@ WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const&
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
const bool useSRGBColorSpace = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0;
|
const bool useSRGBColorSpace = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0;
|
||||||
|
const bool needStencil = (flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0;
|
||||||
initConfig(mConfig, device, capabilities, surfaceSize, useSRGBColorSpace);
|
initConfig(mConfig, device, capabilities, surfaceSize, useSRGBColorSpace);
|
||||||
|
mDepthFormat = selectDepthFormat(device.HasFeature(wgpu::FeatureName::Depth32FloatStencil8),
|
||||||
|
needStencil);
|
||||||
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
|
printSurfaceConfiguration(mConfig, mDepthFormat);
|
||||||
|
#endif
|
||||||
mSurface.Configure(&mConfig);
|
mSurface.Configure(&mConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,12 +259,12 @@ void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
|||||||
if (mConfig.width != currentSurfaceSize.width || mConfig.height != currentSurfaceSize.height) {
|
if (mConfig.width != currentSurfaceSize.width || mConfig.height != currentSurfaceSize.height) {
|
||||||
mConfig.width = currentSurfaceSize.width;
|
mConfig.width = currentSurfaceSize.width;
|
||||||
mConfig.height = currentSurfaceSize.height;
|
mConfig.height = currentSurfaceSize.height;
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printSurfaceConfiguration(mConfig);
|
|
||||||
#endif
|
|
||||||
FWGPU_LOGD << "Resizing to width " << mConfig.width << " height " << mConfig.height
|
FWGPU_LOGD << "Resizing to width " << mConfig.width << " height " << mConfig.height
|
||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
// TODO we may need to ensure no surface texture is flight when we do this. some
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
|
printSurfaceConfiguration(mConfig, mDepthFormat);
|
||||||
|
#endif
|
||||||
|
// TODO we may need to ensure no surface texture is in flight when we do this. some
|
||||||
// synchronization may be necessary
|
// synchronization may be necessary
|
||||||
mSurface.Configure(&mConfig);
|
mSurface.Configure(&mConfig);
|
||||||
}
|
}
|
||||||
@@ -257,7 +281,7 @@ wgpu::TextureView WebGPUSwapChain::getCurrentSurfaceTextureView(
|
|||||||
// Create a view for this surface texture
|
// Create a view for this surface texture
|
||||||
// TODO: review these initiliazations as webgpu pipeline gets mature
|
// TODO: review these initiliazations as webgpu pipeline gets mature
|
||||||
wgpu::TextureViewDescriptor textureViewDescriptor = {
|
wgpu::TextureViewDescriptor textureViewDescriptor = {
|
||||||
.label = "texture_view",
|
.label = "surface_texture_view",
|
||||||
.format = surfaceTexture.texture.GetFormat(),
|
.format = surfaceTexture.texture.GetFormat(),
|
||||||
.dimension = wgpu::TextureViewDimension::e2D,
|
.dimension = wgpu::TextureViewDimension::e2D,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
|
|||||||
@@ -29,10 +29,14 @@ namespace filament::backend {
|
|||||||
class WebGPUSwapChain final : public Platform::SwapChain, HwSwapChain {
|
class WebGPUSwapChain final : public Platform::SwapChain, HwSwapChain {
|
||||||
public:
|
public:
|
||||||
WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
||||||
wgpu::Adapter& adapter, wgpu::Device& device, uint64_t flags);
|
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags);
|
||||||
~WebGPUSwapChain();
|
~WebGPUSwapChain();
|
||||||
|
|
||||||
wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
[[nodiscard]] wgpu::TextureFormat getColorFormat() const { return mConfig.format; }
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::TextureFormat getDepthFormat() const { return mDepthFormat; }
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
||||||
|
|
||||||
void present();
|
void present();
|
||||||
|
|
||||||
@@ -41,6 +45,7 @@ private:
|
|||||||
|
|
||||||
wgpu::Surface mSurface = {};
|
wgpu::Surface mSurface = {};
|
||||||
wgpu::SurfaceConfiguration mConfig = {};
|
wgpu::SurfaceConfiguration mConfig = {};
|
||||||
|
wgpu::TextureFormat mDepthFormat = wgpu::TextureFormat::Undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -98,10 +98,23 @@ wgpu::Adapter WebGPUPlatform::requestAdapter(wgpu::Surface const& surface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||||
// TODO consider passing required features and/or limits
|
// TODO consider passing limits
|
||||||
|
constexpr std::array desiredFeatures = {
|
||||||
|
wgpu::FeatureName::DepthClipControl,
|
||||||
|
wgpu::FeatureName::Depth32FloatStencil8,
|
||||||
|
wgpu::FeatureName::CoreFeaturesAndLimits };
|
||||||
|
std::vector<wgpu::FeatureName> requiredFeatures;
|
||||||
|
requiredFeatures.reserve(desiredFeatures.size());
|
||||||
|
wgpu::SupportedFeatures supportedFeatures;
|
||||||
|
adapter.GetFeatures(&supportedFeatures);
|
||||||
|
std::set_intersection(supportedFeatures.features,
|
||||||
|
supportedFeatures.features + supportedFeatures.featureCount, desiredFeatures.begin(),
|
||||||
|
desiredFeatures.end(), std::back_inserter(requiredFeatures));
|
||||||
wgpu::DeviceDescriptor deviceDescriptor{};
|
wgpu::DeviceDescriptor deviceDescriptor{};
|
||||||
deviceDescriptor.label = "graphics_device";
|
deviceDescriptor.label = "graphics_device";
|
||||||
deviceDescriptor.defaultQueue.label = "default_queue";
|
deviceDescriptor.defaultQueue.label = "default_queue";
|
||||||
|
deviceDescriptor.requiredFeatureCount = requiredFeatures.size();
|
||||||
|
deviceDescriptor.requiredFeatures = requiredFeatures.data();
|
||||||
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
||||||
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
||||||
wgpu::StringView message) {
|
wgpu::StringView message) {
|
||||||
|
|||||||
@@ -33,9 +33,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
||||||
uint32_t expectedHash)
|
uint32_t expectedHash, bool isSrgb)
|
||||||
: mWidth(width),
|
: mWidth(width),
|
||||||
mHeight(height),
|
mHeight(height),
|
||||||
|
mIsSrgb(isSrgb),
|
||||||
mExpectedPixelHash(expectedHash),
|
mExpectedPixelHash(expectedHash),
|
||||||
mFileName(std::move(fileName)) {}
|
mFileName(std::move(fileName)) {}
|
||||||
|
|
||||||
@@ -47,6 +48,10 @@ int ScreenshotParams::height() const {
|
|||||||
return mHeight;
|
return mHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScreenshotParams::isSrgb() const {
|
||||||
|
return mIsSrgb;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ScreenshotParams::expectedHash() const {
|
uint32_t ScreenshotParams::expectedHash() const {
|
||||||
return mExpectedPixelHash;
|
return mExpectedPixelHash;
|
||||||
}
|
}
|
||||||
@@ -147,13 +152,25 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
|
|||||||
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
|
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
|
||||||
internal->bytesFilled = true;
|
internal->bytesFilled = true;
|
||||||
#ifndef FILAMENT_IOS
|
#ifndef FILAMENT_IOS
|
||||||
image::LinearImage image(internal->params.width(), internal->params.width(), 4);
|
image::LinearImage image;
|
||||||
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
|
if (internal->params.isSrgb()) {
|
||||||
internal->params.height(),
|
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
|
||||||
internal->params.width() * 4, (uint8_t*)buffer);
|
internal->params.height(),
|
||||||
|
internal->params.width() * 4, (uint8_t*)buffer);
|
||||||
|
} else {
|
||||||
|
// The image data is already linear, so pass in transforms that simply go from uint8_t
|
||||||
|
// to float. toLinearWithAlpha divides the float values by uint8_t max so there's no
|
||||||
|
// need to scale it to [0, 1]
|
||||||
|
image = image::toLinearWithAlpha<uint8_t>(
|
||||||
|
internal->params.width(), internal->params.height(),
|
||||||
|
internal->params.width() * 4, (uint8_t*) buffer,
|
||||||
|
[](uint8_t value) -> float { return value; },
|
||||||
|
[](filament::math::float4 rgba) -> filament::math::float4 { return rgba; });
|
||||||
|
}
|
||||||
std::string filePath = internal->params.actualFilePath();
|
std::string filePath = internal->params.actualFilePath();
|
||||||
std::ofstream pngStream(filePath, std::ios::binary | std::ios::trunc);
|
std::ofstream pngStream(filePath, std::ios::binary | std::ios::trunc);
|
||||||
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG, image, "",
|
// To avoid going from linear -> sRGB -> linear save the PNG as linear.
|
||||||
|
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG_LINEAR, image, "",
|
||||||
filePath);
|
filePath);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -175,8 +192,12 @@ RenderTargetDump::~RenderTargetDump() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t RenderTargetDump::Internal::hash() const {
|
||||||
|
return utils::hash::murmur3((uint32_t*)bytes.data(), bytes.size() / 4, 0);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t RenderTargetDump::hash() const {
|
uint32_t RenderTargetDump::hash() const {
|
||||||
return utils::hash::murmur3((uint32_t*)mInternal->bytes.data(), mInternal->bytes.size() / 4, 0);
|
return mInternal->hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderTargetDump::bytesFilled() const {
|
bool RenderTargetDump::bytesFilled() const {
|
||||||
@@ -204,9 +225,15 @@ LoadedPng::LoadedPng(std::string filePath) : mFilePath(std::move(filePath)) {
|
|||||||
|
|
||||||
uint32_t LoadedPng::hash() const {
|
uint32_t LoadedPng::hash() const {
|
||||||
EXPECT_THAT(mBytes, testing::Not(testing::IsEmpty()))
|
EXPECT_THAT(mBytes, testing::Not(testing::IsEmpty()))
|
||||||
<< "Failed to load expected test result: " << mFilePath;
|
<< "Failed to load expected test result: " << mFilePath << ".\n"
|
||||||
|
<< "Did you forget to sync CMake after updating the expected image in the source "
|
||||||
|
"directory?";
|
||||||
if (mBytes.empty()) {
|
if (mBytes.empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return utils::hash::murmur3((uint32_t*)mBytes.data(), mBytes.size() / 4, 0);
|
return utils::hash::murmur3((uint32_t*)mBytes.data(), mBytes.size() / 4, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<unsigned char>& LoadedPng::bytes() const {
|
||||||
|
return mBytes;
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,10 +40,12 @@ do { \
|
|||||||
*/
|
*/
|
||||||
class ScreenshotParams {
|
class ScreenshotParams {
|
||||||
public:
|
public:
|
||||||
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash);
|
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash,
|
||||||
|
bool isSrgb = false);
|
||||||
|
|
||||||
int width() const;
|
int width() const;
|
||||||
int height() const;
|
int height() const;
|
||||||
|
bool isSrgb() const;
|
||||||
uint32_t expectedHash() const;
|
uint32_t expectedHash() const;
|
||||||
|
|
||||||
static std::string actualDirectoryPath();
|
static std::string actualDirectoryPath();
|
||||||
@@ -56,6 +58,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
int mWidth;
|
int mWidth;
|
||||||
int mHeight;
|
int mHeight;
|
||||||
|
bool mIsSrgb;
|
||||||
uint32_t mExpectedPixelHash;
|
uint32_t mExpectedPixelHash;
|
||||||
std::string mFileName;
|
std::string mFileName;
|
||||||
};
|
};
|
||||||
@@ -92,6 +95,8 @@ private:
|
|||||||
ScreenshotParams params;
|
ScreenshotParams params;
|
||||||
std::atomic<bool> bytesFilled = false;
|
std::atomic<bool> bytesFilled = false;
|
||||||
std::vector<unsigned char> bytes;
|
std::vector<unsigned char> bytes;
|
||||||
|
|
||||||
|
uint32_t hash() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need a memory location that won't be invalidated to pass to GPU callbacks as they can't
|
// We need a memory location that won't be invalidated to pass to GPU callbacks as they can't
|
||||||
@@ -105,6 +110,8 @@ public:
|
|||||||
|
|
||||||
uint32_t hash() const;
|
uint32_t hash() const;
|
||||||
|
|
||||||
|
const std::vector<unsigned char>& bytes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mFilePath;
|
std::string mFilePath;
|
||||||
std::vector<unsigned char> mBytes;
|
std::vector<unsigned char> mBytes;
|
||||||
|
|||||||
@@ -55,8 +55,10 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
|||||||
prog.descriptorBindings(1, bindingsInfo);
|
prog.descriptorBindings(1, bindingsInfo);
|
||||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||||
|
|
||||||
mDescriptorSetLayout = cleanup.add(
|
if (!kLayouts.empty()) {
|
||||||
api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
mDescriptorSetLayout =
|
||||||
|
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
Cleanup& mCleanup;
|
Cleanup& mCleanup;
|
||||||
filament::backend::ProgramHandle mProgram;
|
filament::backend::ProgramHandle mProgram;
|
||||||
|
// This will be a null handle if there are no uniforms.
|
||||||
filament::backend::DescriptorSetLayoutHandle mDescriptorSetLayout;
|
filament::backend::DescriptorSetLayoutHandle mDescriptorSetLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,14 @@
|
|||||||
#include "BackendTest.h"
|
#include "BackendTest.h"
|
||||||
|
|
||||||
// skipEnvironment must be a test::SkipEnvironment
|
// skipEnvironment must be a test::SkipEnvironment
|
||||||
#define SKIP_IF(skipEnvironment) \
|
// rationale must be a string
|
||||||
do { \
|
#define SKIP_IF(skipEnvironment, rationale) \
|
||||||
SkipEnvironment skip(skipEnvironment); \
|
do { \
|
||||||
if (skip.matches()) { \
|
SkipEnvironment skip(skipEnvironment); \
|
||||||
GTEST_SKIP() << "Skipping test as the " << skip.describe(); \
|
if (skip.matches()) { \
|
||||||
} \
|
GTEST_SKIP() << "Skipping test as the " << skip.describe() << "\n" \
|
||||||
|
<< " This test can't run there because " << rationale; \
|
||||||
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 915 B |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
BIN
filament/backend/test/expected_images/pushConstants.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
62
filament/backend/test/move_actual_images_to_expected.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import os, shutil, argparse, typing
|
||||||
|
|
||||||
|
def match_sufffix(file_name: str, suffix: str, accepted_prefixes: typing.List[str]) -> str:
|
||||||
|
"""
|
||||||
|
Check if the file name is one of the searched for ones with the given suffix and if so return it.
|
||||||
|
:param accepted_prefixes: If None accepts any prefix
|
||||||
|
:return: file_name with the suffix removed or "" if it doesn't match. This does mean a string that
|
||||||
|
is just the suffix is considered to not match as it will return the empty string.
|
||||||
|
"""
|
||||||
|
if file_name.endswith(suffix):
|
||||||
|
prefix = file_name.removesuffix(suffix)
|
||||||
|
if accepted_prefixes is None or prefix in accepted_prefixes:
|
||||||
|
return prefix
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def replace_file_names(path: str, removed: str, replacement: str = "", output_path: str = "",
|
||||||
|
prefixes: typing.List[str] = None):
|
||||||
|
if not output_path:
|
||||||
|
output_path = path
|
||||||
|
for file_name in os.listdir(path=path):
|
||||||
|
prefix = match_sufffix(file_name, removed, prefixes)
|
||||||
|
if prefix:
|
||||||
|
# Remove the prefix from the list so that prefixes is the list of intended but not yet found
|
||||||
|
# files.
|
||||||
|
if prefixes is not None:
|
||||||
|
prefixes.remove(prefix)
|
||||||
|
new_file_name = prefix + replacement
|
||||||
|
new_file_path = os.path.join(output_path, new_file_name)
|
||||||
|
old_file_path = os.path.join(path, file_name)
|
||||||
|
print(f'{old_file_path} to {new_file_path}')
|
||||||
|
shutil.move(old_file_path, new_file_path)
|
||||||
|
if prefixes is not None:
|
||||||
|
for unfound_prefix in prefixes:
|
||||||
|
print(f'Failed to find {unfound_prefix}_actual.png')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(prog='Backend Test File Renamer',
|
||||||
|
description='Moves actual generated test images to the expected '
|
||||||
|
'images directory, to update the test requirements. '
|
||||||
|
'test_cases accepts multiple arguments that should '
|
||||||
|
'be the name of the expected image file without the '
|
||||||
|
'.png suffix. Also --all can be passed to copy all '
|
||||||
|
'images.\n'
|
||||||
|
'Remember to sync CMake after running this to move '
|
||||||
|
'the new expected images to the binary directory.')
|
||||||
|
parser.add_argument('-i', '--input_path')
|
||||||
|
parser.add_argument('-o', '--output_path', default="./expected_images")
|
||||||
|
parser.add_argument('-t', '--test_cases', action='extend', nargs='*')
|
||||||
|
parser.add_argument('-a', '--all', action='store_true')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
input_path = "."
|
||||||
|
if args.input_path:
|
||||||
|
input_path = args.input_path
|
||||||
|
|
||||||
|
prefixes = args.test_cases
|
||||||
|
if args.all:
|
||||||
|
prefixes = None
|
||||||
|
|
||||||
|
replace_file_names(path=input_path, output_path=args.output_path, removed="_actual.png",
|
||||||
|
replacement=".png", prefixes=prefixes)
|
||||||
@@ -25,7 +25,7 @@ using namespace filament::backend;
|
|||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
TEST_F(BackendTest, FrameScheduledCallback) {
|
TEST_F(BackendTest, FrameScheduledCallback) {
|
||||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
|
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
|
||||||
|
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
@@ -84,7 +84,7 @@ TEST_F(BackendTest, FrameScheduledCallback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BackendTest, FrameCompletedCallback) {
|
TEST_F(BackendTest, FrameCompletedCallback) {
|
||||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
|
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
|
||||||
|
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "Lifetimes.h"
|
#include "Lifetimes.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
|
#include "Skip.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
@@ -98,6 +99,9 @@ struct MaterialParams {
|
|||||||
// The problems are caused by both uploading and rendering into the same texture, since the OpenGL
|
// The problems are caused by both uploading and rendering into the same texture, since the OpenGL
|
||||||
// backend's readPixels does not work correctly with textures that have image data uploaded.
|
// backend's readPixels does not work correctly with textures that have image data uploaded.
|
||||||
TEST_F(BackendTest, FeedbackLoops) {
|
TEST_F(BackendTest, FeedbackLoops) {
|
||||||
|
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL),
|
||||||
|
"OpenGL image is upside down due to readPixels failing for texture with uploaded image "
|
||||||
|
"data");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
@@ -239,7 +243,7 @@ TEST_F(BackendTest, FeedbackLoops) {
|
|||||||
// seems to be un-reliable on some GPU's.
|
// seems to be un-reliable on some GPU's.
|
||||||
if (frame == kNumFrames - 1) {
|
if (frame == kNumFrames - 1) {
|
||||||
EXPECT_IMAGE(renderTargets[0], getExpectations(),
|
EXPECT_IMAGE(renderTargets[0], getExpectations(),
|
||||||
ScreenshotParams(kTexWidth, kTexHeight, "FeedbackLoops", 0x70695aa1));
|
ScreenshotParams(kTexWidth, kTexHeight, "FeedbackLoops", 4192780705));
|
||||||
}
|
}
|
||||||
|
|
||||||
api.flush();
|
api.flush();
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ void main() {
|
|||||||
})";
|
})";
|
||||||
|
|
||||||
TEST_F(BackendTest, PushConstants) {
|
TEST_F(BackendTest, PushConstants) {
|
||||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
|
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
|
||||||
|
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Lifetimes.h"
|
#include "Lifetimes.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
#include "SharedShaders.h"
|
#include "SharedShaders.h"
|
||||||
|
#include "Skip.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
@@ -45,6 +46,7 @@ Shader createShader(DriverApi& api, Cleanup& cleanup, Backend backend) {
|
|||||||
|
|
||||||
// Rendering an external image without setting any data should not crash.
|
// Rendering an external image without setting any data should not crash.
|
||||||
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||||
|
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
@@ -111,6 +113,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BackendTest, RenderExternalImage) {
|
TEST_F(BackendTest, RenderExternalImage) {
|
||||||
|
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Lifetimes.h"
|
#include "Lifetimes.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
#include "SharedShaders.h"
|
#include "SharedShaders.h"
|
||||||
|
#include "Skip.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
|
|
||||||
using namespace filament;
|
using namespace filament;
|
||||||
@@ -161,6 +162,7 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||||
|
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL), "Stencil isn't applied");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
@@ -237,7 +239,7 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
|||||||
api.endFrame(0);
|
api.endFrame(0);
|
||||||
|
|
||||||
EXPECT_IMAGE(renderTarget1, getExpectations(),
|
EXPECT_IMAGE(renderTarget1, getExpectations(),
|
||||||
ScreenshotParams(512, 512, "StencilBufferAutoResolve", 0x6CEFAC8F));
|
ScreenshotParams(512, 512, "StencilBufferAutoResolve", 3353562179));
|
||||||
|
|
||||||
flushAndWait();
|
flushAndWait();
|
||||||
getDriver().purge();
|
getDriver().purge();
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ void DependencyGraph::clear() noexcept {
|
|||||||
mNodes.clear();
|
mNodes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DependencyGraph::export_graphviz(utils::io::ostream& out, char const* name) {
|
void DependencyGraph::export_graphviz(utils::io::ostream& out, char const* name) const noexcept {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const char* graphName = name ? name : "graph";
|
const char* graphName = name ? name : "graph";
|
||||||
out << "digraph \"" << graphName << "\" {\n";
|
out << "digraph \"" << graphName << "\" {\n";
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ bool FrameGraph::isAcyclic() const noexcept {
|
|||||||
return mGraph.isAcyclic();
|
return mGraph.isAcyclic();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameGraph::export_graphviz(utils::io::ostream& out, char const* name) {
|
void FrameGraph::export_graphviz(utils::io::ostream& out, char const* name) const noexcept {
|
||||||
mGraph.export_graphviz(out, name);
|
mGraph.export_graphviz(out, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +573,11 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
|
|||||||
info.setResources(std::move(resources));
|
info.setResources(std::move(resources));
|
||||||
info.setPasses(std::move(passes));
|
info.setPasses(std::move(passes));
|
||||||
|
|
||||||
|
// Generate GraphViz DOT data
|
||||||
|
utils::io::sstream out;
|
||||||
|
this->export_graphviz(out, viewName);
|
||||||
|
info.setGraphvizData(utils::CString(out.c_str()));
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
#else
|
#else
|
||||||
return fgviewer::FrameGraphInfo();
|
return fgviewer::FrameGraphInfo();
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ public:
|
|||||||
bool isAcyclic() const noexcept;
|
bool isAcyclic() const noexcept;
|
||||||
|
|
||||||
//! export a graphviz view of the graph
|
//! export a graphviz view of the graph
|
||||||
void export_graphviz(utils::io::ostream& out, const char* name = nullptr);
|
void export_graphviz(utils::io::ostream& out, const char* name = nullptr) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export a fgviewer::FrameGraphInfo for current graph.
|
* Export a fgviewer::FrameGraphInfo for current graph.
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public:
|
|||||||
bool isEdgeValid(Edge const* edge) const noexcept;
|
bool isEdgeValid(Edge const* edge) const noexcept;
|
||||||
|
|
||||||
//! export a graphviz view of the graph
|
//! export a graphviz view of the graph
|
||||||
void export_graphviz(utils::io::ostream& out, const char* name = nullptr);
|
void export_graphviz(utils::io::ostream& out, const char* name = nullptr) const noexcept;
|
||||||
|
|
||||||
bool isAcyclic() const noexcept;
|
bool isAcyclic() const noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -78,18 +78,23 @@ public:
|
|||||||
// The incoming passes should be sorted by the execution order.
|
// The incoming passes should be sorted by the execution order.
|
||||||
void setPasses(std::vector<Pass> sortedPasses);
|
void setPasses(std::vector<Pass> sortedPasses);
|
||||||
|
|
||||||
|
void setGraphvizData(utils::CString data);
|
||||||
|
|
||||||
const char* getViewName() const;
|
const char* getViewName() const;
|
||||||
|
|
||||||
const std::vector<Pass>& getPasses() const;
|
const std::vector<Pass>& getPasses() const;
|
||||||
|
|
||||||
const std::unordered_map<ResourceId, Resource>& getResources() const;
|
const std::unordered_map<ResourceId, Resource>& getResources() const;
|
||||||
|
|
||||||
|
const char* getGraphvizData() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utils::CString viewName;
|
utils::CString viewName;
|
||||||
// The order of the passes in the vector indicates the execution
|
// The order of the passes in the vector indicates the execution
|
||||||
// order of the passes.
|
// order of the passes.
|
||||||
std::vector<Pass> passes;
|
std::vector<Pass> passes;
|
||||||
std::unordered_map<ResourceId, Resource> resources;
|
std::unordered_map<ResourceId, Resource> resources;
|
||||||
|
utils::CString graphvizData;
|
||||||
};
|
};
|
||||||
} // namespace filament::fgviewer
|
} // namespace filament::fgviewer
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ FrameGraphInfo::~FrameGraphInfo() = default;
|
|||||||
FrameGraphInfo::FrameGraphInfo(FrameGraphInfo&& rhs) noexcept = default;
|
FrameGraphInfo::FrameGraphInfo(FrameGraphInfo&& rhs) noexcept = default;
|
||||||
|
|
||||||
bool FrameGraphInfo::operator==(const FrameGraphInfo& rhs) const {
|
bool FrameGraphInfo::operator==(const FrameGraphInfo& rhs) const {
|
||||||
|
// We skip checking graphviz here since checking passes and resources should be enough.
|
||||||
return viewName == rhs.viewName
|
return viewName == rhs.viewName
|
||||||
&& passes == rhs.passes
|
&& passes == rhs.passes
|
||||||
&& resources == rhs.resources;
|
&& resources == rhs.resources;
|
||||||
@@ -66,6 +67,10 @@ void FrameGraphInfo::setPasses(std::vector<Pass> sortedPasses) {
|
|||||||
passes = std::move(sortedPasses);
|
passes = std::move(sortedPasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FrameGraphInfo::setGraphvizData(utils::CString data) {
|
||||||
|
graphvizData = std::move(data);
|
||||||
|
}
|
||||||
|
|
||||||
const char* FrameGraphInfo::getViewName() const {
|
const char* FrameGraphInfo::getViewName() const {
|
||||||
return viewName.c_str_safe();
|
return viewName.c_str_safe();
|
||||||
}
|
}
|
||||||
@@ -79,4 +84,8 @@ const std::unordered_map<ResourceId, FrameGraphInfo::Resource>&
|
|||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* FrameGraphInfo::getGraphvizData() const {
|
||||||
|
return graphvizData.c_str_safe();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace filament::fgviewer
|
} // namespace filament::fgviewer
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
namespace filament::fgviewer {
|
namespace filament::fgviewer {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void writeJSONString(std::ostream& os, const char* str) {
|
void writeJSONString(std::ostream& os, const char* str) {
|
||||||
os << '"';
|
os << '"';
|
||||||
const char* p = str;
|
const char* p = str;
|
||||||
@@ -46,7 +47,7 @@ void writeJSONString(std::ostream& os, const char* str) {
|
|||||||
void writeViewName(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
void writeViewName(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
||||||
os << " \"viewName\": ";
|
os << " \"viewName\": ";
|
||||||
writeJSONString(os, frameGraph.getViewName());
|
writeJSONString(os, frameGraph.getViewName());
|
||||||
os << ",\n";
|
os << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeResourceIds(std::ostream& os, const std::vector<ResourceId>& resources) {
|
void writeResourceIds(std::ostream& os, const std::vector<ResourceId>& resources) {
|
||||||
@@ -80,7 +81,7 @@ void writePasses(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
|||||||
if (i + 1 < passes.size()) os << ",";
|
if (i + 1 < passes.size()) os << ",";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
}
|
}
|
||||||
os << " ],\n";
|
os << " ]\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeResources(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
void writeResources(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
||||||
@@ -114,6 +115,15 @@ void writeResources(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
|||||||
}
|
}
|
||||||
os << " }\n";
|
os << " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeGraphviz(std::ostream& os, const FrameGraphInfo& frameGraph) {
|
||||||
|
const char* graphvizString = frameGraph.getGraphvizData();
|
||||||
|
|
||||||
|
os << " \"graphviz\": ";
|
||||||
|
writeJSONString(os, graphvizString);
|
||||||
|
os << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous
|
} // anonymous
|
||||||
|
|
||||||
const char* JsonWriter::getJsonString() const {
|
const char* JsonWriter::getJsonString() const {
|
||||||
@@ -128,8 +138,12 @@ bool JsonWriter::writeFrameGraphInfo(const FrameGraphInfo& frameGraph) {
|
|||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
writeViewName(os, frameGraph);
|
writeViewName(os, frameGraph);
|
||||||
|
os << ",\n";
|
||||||
writePasses(os, frameGraph);
|
writePasses(os, frameGraph);
|
||||||
|
os << ",\n";
|
||||||
writeResources(os, frameGraph);
|
writeResources(os, frameGraph);
|
||||||
|
os << ",\n";
|
||||||
|
writeGraphviz(os, frameGraph);
|
||||||
|
|
||||||
|
|
||||||
mJsonString = utils::CString(os.str().c_str());
|
mJsonString = utils::CString(os.str().c_str());
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module";
|
import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module";
|
||||||
|
import { graphviz } from "https://cdn.skypack.dev/d3-graphviz@5.1.0";
|
||||||
|
import * as d3 from "https://cdn.skypack.dev/d3@7";
|
||||||
|
|
||||||
const kUntitledPlaceholder = "Untitled View";
|
const kUntitledPlaceholder = "Untitled View";
|
||||||
|
|
||||||
@@ -33,6 +35,11 @@ const READ_WRITE_COLOR = '#ffeb99';
|
|||||||
const DEFAULT_COLOR = '#ffffff';
|
const DEFAULT_COLOR = '#ffffff';
|
||||||
const SUBRESOURCE_COLOR = '#d3d3d3';
|
const SUBRESOURCE_COLOR = '#d3d3d3';
|
||||||
|
|
||||||
|
// Constants for view mode toggle
|
||||||
|
const VIEW_TOGGLE_INACTIVE_COLOR = '#292929';
|
||||||
|
const VIEW_TOGGLE_UNSELECTED_COLOR = '#3f4cbe';
|
||||||
|
const VIEW_TOGGLE_SELECTED_COLOR = '#2c3892';
|
||||||
|
|
||||||
const RESOURCE_USAGE_TYPE_READ = 'read';
|
const RESOURCE_USAGE_TYPE_READ = 'read';
|
||||||
const RESOURCE_USAGE_TYPE_WRITE = 'write';
|
const RESOURCE_USAGE_TYPE_WRITE = 'write';
|
||||||
const RESOURCE_USAGE_TYPE_NO_ACCESS = 'no-access';
|
const RESOURCE_USAGE_TYPE_NO_ACCESS = 'no-access';
|
||||||
@@ -40,6 +47,10 @@ const RESOURCE_USAGE_TYPE_READ_WRITE = 'read-write';
|
|||||||
|
|
||||||
const IS_SUBRESOURCE_KEY = 'is_subresource_of'
|
const IS_SUBRESOURCE_KEY = 'is_subresource_of'
|
||||||
|
|
||||||
|
// View mode constants
|
||||||
|
const VIEW_MODE_TABLE = 'table';
|
||||||
|
const VIEW_MODE_GRAPHVIZ = 'graphviz';
|
||||||
|
|
||||||
class MenuSection extends LitElement {
|
class MenuSection extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@@ -150,19 +161,35 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
color: ${FOREGROUND_COLOR};
|
color: ${FOREGROUND_COLOR};
|
||||||
}
|
}
|
||||||
.resource-title {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-size: ${REGULAR_FONT_SIZE}px;
|
|
||||||
color: ${UNSELECTED_COLOR};
|
|
||||||
}
|
|
||||||
.resource-content {
|
.resource-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-size: ${REGULAR_FONT_SIZE}px;
|
font-size: ${REGULAR_FONT_SIZE}px;
|
||||||
color: ${UNSELECTED_COLOR};
|
color: ${UNSELECTED_COLOR};
|
||||||
}
|
}
|
||||||
|
.view-mode-selector {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.view-toggle {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: ${this.connected ? VIEW_TOGGLE_UNSELECTED_COLOR:VIEW_TOGGLE_INACTIVE_COLOR};
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.view-toggle.active {
|
||||||
|
background-color: ${this.connected ? VIEW_TOGGLE_SELECTED_COLOR:VIEW_TOGGLE_INACTIVE_COLOR};
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +198,7 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
connected: {type: Boolean, attribute: 'connected'},
|
connected: {type: Boolean, attribute: 'connected'},
|
||||||
selectedFrameGraph: {type: String, attribute: 'selected-framegraph'},
|
selectedFrameGraph: {type: String, attribute: 'selected-framegraph'},
|
||||||
selectedResourceId: {type: Number, attribute: 'selected-resource'},
|
selectedResourceId: {type: Number, attribute: 'selected-resource'},
|
||||||
|
viewMode: {type: String, attribute: 'view-mode'},
|
||||||
|
|
||||||
database: {type: Object, state: true},
|
database: {type: Object, state: true},
|
||||||
framegraphs: {type: Array, state: true},
|
framegraphs: {type: Array, state: true},
|
||||||
@@ -182,6 +210,7 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.framegraphs = [];
|
this.framegraphs = [];
|
||||||
this.database = {};
|
this.database = {};
|
||||||
|
this.viewMode = VIEW_MODE_TABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(props) {
|
updated(props) {
|
||||||
@@ -199,7 +228,6 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_handleFrameGraphClick(ev) {
|
_handleFrameGraphClick(ev) {
|
||||||
this.dispatchEvent(new CustomEvent('select-framegraph', {
|
this.dispatchEvent(new CustomEvent('select-framegraph', {
|
||||||
detail: ev,
|
detail: ev,
|
||||||
@@ -208,41 +236,85 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_handleViewModeClick(mode) {
|
||||||
|
this.dispatchEvent(new CustomEvent('change-view-mode', {
|
||||||
|
detail: mode,
|
||||||
|
bubbles: true,
|
||||||
|
composed: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
_findCurrentResource() {
|
_findCurrentResource() {
|
||||||
if (!this.selectedFrameGraph)
|
if (!this.selectedFrameGraph)
|
||||||
return null;
|
return null;
|
||||||
const frameGraph = this.database[this.selectedFrameGraph];
|
|
||||||
return Object.values(frameGraph?.resources)
|
const resources = this.database[this.selectedFrameGraph]?.resources;
|
||||||
.find(resource => resource.id === this.selectedResourceId) || null;
|
if (resources) {
|
||||||
|
const resource = resources[this.selectedResourceId];
|
||||||
|
if (resource) {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const renderFrameGraphs = (title) => {
|
const renderFrameGraphs = (title) => {
|
||||||
if (!this.framegraphs.length) return nothing;
|
if (!this.framegraphs.length)
|
||||||
|
return nothing;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<menu-section title="${title}">
|
<menu-section title="${title}">
|
||||||
${this.framegraphs.map(({ fgid, name }) => html`
|
${this.selectedFrameGraph ? html`
|
||||||
<div class="framegraph"
|
<div class="view-mode-selector">
|
||||||
@click="${() => this._handleFrameGraphClick(fgid)}"
|
<div class="view-toggle ${this.viewMode === VIEW_MODE_TABLE ? 'active' : ''}"
|
||||||
data-id="${fgid}">
|
@click="${() => this._handleViewModeClick(VIEW_MODE_TABLE)}">
|
||||||
${fgid === this.selectedFrameGraph ? '● ' : ''}${name}
|
Table Mode
|
||||||
</div>
|
</div>
|
||||||
`)}
|
<div class="view-toggle ${this.viewMode === VIEW_MODE_GRAPHVIZ ? 'active' : ''}"
|
||||||
|
@click="${() => this._handleViewModeClick(VIEW_MODE_GRAPHVIZ)}">
|
||||||
|
Graph Mode
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : nothing}
|
||||||
|
|
||||||
|
<div class="framegraphs">
|
||||||
|
${this.framegraphs.map(({fgid, name}) => {
|
||||||
|
const isSelected = this.selectedFrameGraph === fgid;
|
||||||
|
return html`
|
||||||
|
<div @click="${() => this._handleFrameGraphClick(fgid)}"
|
||||||
|
class="framegraph ${isSelected ? 'selected' : ''}">
|
||||||
|
${isSelected ? '● ' : ''}${name}
|
||||||
|
</div>`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</menu-section>
|
</menu-section>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderResourceDetails = (title) => {
|
const renderResourceDetails = (title) => {
|
||||||
const currentResource = this._findCurrentResource();
|
const currentResource = this._findCurrentResource();
|
||||||
if (!currentResource) return nothing;
|
if (!currentResource)
|
||||||
|
return nothing;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<menu-section title="${title}">
|
<menu-section title="${title}">
|
||||||
<div class="resource-title">${currentResource.id}: ${currentResource.name}</div>
|
<div class="resource-content">
|
||||||
${currentResource.properties?.map(({ key, value }) => html`
|
<div><b>Name:</b> ${currentResource.name}</div>
|
||||||
<div class="resource-content">${key}: ${value}</div>
|
</div>
|
||||||
`)}
|
<div class="resource-content">
|
||||||
|
<div><b>ID:</b> ${currentResource.id}</div>
|
||||||
|
</div>
|
||||||
|
${currentResource.properties.length > 0 ? html`
|
||||||
|
<div class="resource-content">
|
||||||
|
<div><b>Properties:</b></div>
|
||||||
|
<ul>
|
||||||
|
${currentResource.properties.map(prop => html`
|
||||||
|
<li>${prop.key}: ${prop.value}</li>
|
||||||
|
`)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
</menu-section>
|
</menu-section>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
@@ -256,7 +328,6 @@ class FrameGraphSidePanel extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("framegraph-sidepanel", FrameGraphSidePanel);
|
customElements.define("framegraph-sidepanel", FrameGraphSidePanel);
|
||||||
@@ -480,7 +551,8 @@ class FrameGraphTable extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.frameGraphData?.passes || !this.frameGraphData?.resources) return nothing;
|
if (!this.frameGraphData?.passes || !this.frameGraphData?.resources)
|
||||||
|
return nothing;
|
||||||
|
|
||||||
const allPasses = this.frameGraphData.passes;
|
const allPasses = this.frameGraphData.passes;
|
||||||
const resources = Object.values(this.frameGraphData.resources);
|
const resources = Object.values(this.frameGraphData.resources);
|
||||||
@@ -505,6 +577,82 @@ class FrameGraphTable extends LitElement {
|
|||||||
|
|
||||||
customElements.define("framegraph-table", FrameGraphTable);
|
customElements.define("framegraph-table", FrameGraphTable);
|
||||||
|
|
||||||
|
class GraphvizView extends LitElement {
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graphviz-container {
|
||||||
|
margin-left: 300px;
|
||||||
|
height: 100vh;
|
||||||
|
width: calc(100% - 300px);
|
||||||
|
overflow: auto;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#graph {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
graphvizData: {type: String, state: true},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.graphvizData = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProps) {
|
||||||
|
if (changedProps.has('graphvizData')) {
|
||||||
|
this._renderGraphviz();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderGraphviz() {
|
||||||
|
if (!this.graphvizData)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const container = this.renderRoot.querySelector('#graphviz-view');
|
||||||
|
if (!container)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const viz = d3.select(container)
|
||||||
|
.graphviz({ useWorker: false })
|
||||||
|
.zoom(true)
|
||||||
|
.fit(true);
|
||||||
|
|
||||||
|
viz.renderDot(this.graphvizData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to render graphviz:', error);
|
||||||
|
container.innerHTML = `<div class="error">Failed to render graphviz: ${error.message}</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if(!this.graphvizData)
|
||||||
|
return nothing;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="graphviz-container">
|
||||||
|
<div id="graphviz-view"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("graphviz-view", GraphvizView);
|
||||||
|
|
||||||
class FrameGraphViewer extends LitElement {
|
class FrameGraphViewer extends LitElement {
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
@@ -523,6 +671,10 @@ class FrameGraphViewer extends LitElement {
|
|||||||
get _framegraphTable() {
|
get _framegraphTable() {
|
||||||
return this.renderRoot.querySelector('#table');
|
return this.renderRoot.querySelector('#table');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _graphvizView() {
|
||||||
|
return this.renderRoot.querySelector('#graphviz');
|
||||||
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
const isConnected = () => this.connected;
|
const isConnected = () => this.connected;
|
||||||
@@ -535,6 +687,7 @@ class FrameGraphViewer extends LitElement {
|
|||||||
let fgInfo = await fetchFrameGraph(fgid);
|
let fgInfo = await fetchFrameGraph(fgid);
|
||||||
this.database[fgInfo.fgid] = fgInfo;
|
this.database[fgInfo.fgid] = fgInfo;
|
||||||
this._framegraphTable.frameGraphData = fgInfo;
|
this._framegraphTable.frameGraphData = fgInfo;
|
||||||
|
this._graphvizView.graphvizData = fgInfo.graphviz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -555,6 +708,7 @@ class FrameGraphViewer extends LitElement {
|
|||||||
this.database = {};
|
this.database = {};
|
||||||
this.selectedFrameGraph = null;
|
this.selectedFrameGraph = null;
|
||||||
this.selectedResourceId = -1;
|
this.selectedResourceId = -1;
|
||||||
|
this.viewMode = VIEW_MODE_TABLE;
|
||||||
this.init();
|
this.init();
|
||||||
|
|
||||||
this.addEventListener('select-framegraph',
|
this.addEventListener('select-framegraph',
|
||||||
@@ -568,6 +722,12 @@ class FrameGraphViewer extends LitElement {
|
|||||||
this.selectedResourceId = ev.detail;
|
this.selectedResourceId = ev.detail;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.addEventListener('change-view-mode',
|
||||||
|
(ev) => {
|
||||||
|
this.viewMode = ev.detail;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -576,6 +736,7 @@ class FrameGraphViewer extends LitElement {
|
|||||||
database: {type: Object, state: true},
|
database: {type: Object, state: true},
|
||||||
selectedFrameGraph: {type: String, state: true},
|
selectedFrameGraph: {type: String, state: true},
|
||||||
selectedResourceId: {type: Number, state: true},
|
selectedResourceId: {type: Number, state: true},
|
||||||
|
viewMode: {type: String, state: true},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,6 +744,7 @@ class FrameGraphViewer extends LitElement {
|
|||||||
if (props.has('selectedFrameGraph') || props.has('database')) {
|
if (props.has('selectedFrameGraph') || props.has('database')) {
|
||||||
const framegraph = this._getFrameGraph();
|
const framegraph = this._getFrameGraph();
|
||||||
this._framegraphTable.frameGraphData = framegraph;
|
this._framegraphTable.frameGraphData = framegraph;
|
||||||
|
this._graphvizView.graphvizData = framegraph?.graphviz;
|
||||||
this._sidePanel.database = this.database;
|
this._sidePanel.database = this.database;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,13 +755,21 @@ class FrameGraphViewer extends LitElement {
|
|||||||
<framegraph-sidepanel id="sidepanel"
|
<framegraph-sidepanel id="sidepanel"
|
||||||
?connected="${this.connected}"
|
?connected="${this.connected}"
|
||||||
selected-framegraph="${this.selectedFrameGraph}"
|
selected-framegraph="${this.selectedFrameGraph}"
|
||||||
selected-resource="${this.selectedResourceId}">
|
selected-resource="${this.selectedResourceId}"
|
||||||
|
view-mode="${this.viewMode}">
|
||||||
</framegraph-sidepanel>
|
</framegraph-sidepanel>
|
||||||
|
|
||||||
<framegraph-table id="table"
|
<framegraph-table id="table"
|
||||||
|
style="display: ${this.viewMode === VIEW_MODE_TABLE ? 'block' : 'none'};"
|
||||||
?connected="${this.connected}"
|
?connected="${this.connected}"
|
||||||
selected-framegraph="${this.selectedFrameGraph}"
|
selected-framegraph="${this.selectedFrameGraph}"
|
||||||
selected-resource="${this.selectedResourceId}">
|
selected-resource="${this.selectedResourceId}">
|
||||||
</framegraph-table>
|
</framegraph-table>
|
||||||
|
|
||||||
|
<graphviz-view id="graphviz"
|
||||||
|
style="display: ${this.viewMode === VIEW_MODE_GRAPHVIZ ? 'block' : 'none'};"
|
||||||
|
framegraph-id="${this.selectedFrameGraph}">
|
||||||
|
</graphviz-view>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
|||||||
set -e
|
set -e
|
||||||
fi
|
fi
|
||||||
|
|
||||||
os_name=$(uname -s)
|
OS_NAME=$(uname -s)
|
||||||
LLVM_VERSION=16
|
LLVM_VERSION=${GITHUB_LLVM_VERSION-16}
|
||||||
MESA_VERSION=${MESA_VERSION-24.2.1}
|
MESA_VERSION=${GITHUB_MESA_VERSION-24.2.1}
|
||||||
ORIG_DIR=$(pwd)
|
ORIG_DIR=$(pwd)
|
||||||
MESA_DIR=${MESA_DIR-${ORIG_DIR}/mesa}
|
MESA_DIR=${MESA_DIR-${ORIG_DIR}/mesa}
|
||||||
|
|
||||||
if [[ "$os_name" == "Linux" ]]; then
|
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||||
sudo apt install python3-venv
|
sudo apt install python3-venv
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ done
|
|||||||
deactivate
|
deactivate
|
||||||
|
|
||||||
# Install system deps
|
# Install system deps
|
||||||
if [[ "$os_name" == "Linux" ]]; then
|
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
# We only want to do this if it is a CI machine.
|
# We only want to do this if it is a CI machine.
|
||||||
sudo apt-get -y remove llvm-*
|
sudo apt-get -y remove llvm-*
|
||||||
@@ -64,18 +64,17 @@ if [[ "$os_name" == "Linux" ]]; then
|
|||||||
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
|
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
|
||||||
set -e
|
set -e
|
||||||
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
|
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
|
||||||
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}}
|
CLANG_VERSION=${CURRENT_CLANG_VERSION:-${LLVM_VERSION}}
|
||||||
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${LLVM_VERSION}}
|
sudo apt-get -y install clang-${CLANG_VERSION} \
|
||||||
sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \
|
libc++-${CLANG_VERSION}-dev \
|
||||||
libc++-${GITHUB_CLANG_VERSION}-dev \
|
libc++abi-${CLANG_VERSION}-dev \
|
||||||
libc++abi-${GITHUB_CLANG_VERSION}-dev \
|
|
||||||
llvm-${LLVM_VERSION} \
|
llvm-${LLVM_VERSION} \
|
||||||
llvm-${LLVM_VERSION}-{dev,tools,runtime}
|
llvm-${LLVM_VERSION}-{dev,tools,runtime}
|
||||||
! command -v clang > /dev/null 2>&1 && \
|
! command -v clang > /dev/null 2>&1 && \
|
||||||
sudo ln -s /usr/bin/clang-${GITHUB_CLANG_VERSION} /usr/bin/clang && \
|
sudo ln -s /usr/bin/clang-${CLANG_VERSION} /usr/bin/clang && \
|
||||||
sudo ln -s /usr/bin/clang++-${GITHUB_CLANG_VERSION} /usr/bin/clang++
|
sudo ln -s /usr/bin/clang++-${CLANG_VERSION} /usr/bin/clang++
|
||||||
fi # [[ "$GITHUB_WORKFLOW" ]]
|
fi # [[ "$GITHUB_WORKFLOW" ]]
|
||||||
elif [[ "$os_name" == "Darwin" ]]; then
|
elif [[ "$OS_NAME" == "Darwin" ]]; then
|
||||||
if [[ ! "$GITHUB_WORKFLOW" ]]; then
|
if [[ ! "$GITHUB_WORKFLOW" ]]; then
|
||||||
if [ ! command -v brew > /dev/null 2>&1 ]; then
|
if [ ! command -v brew > /dev/null 2>&1 ]; then
|
||||||
echo "Error: need to install homebrew to continue"
|
echo "Error: need to install homebrew to continue"
|
||||||
@@ -83,7 +82,7 @@ elif [[ "$os_name" == "Darwin" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
|
||||||
fi # [[ "$os_name" == x ]]
|
fi # [[ "$OS_NAME" == x ]]
|
||||||
|
|
||||||
LOCAL_LDFLAGS=${LDFLAGS}
|
LOCAL_LDFLAGS=${LDFLAGS}
|
||||||
LOCAL_CPPFLAGS=${CPPFLAGS}
|
LOCAL_CPPFLAGS=${CPPFLAGS}
|
||||||
@@ -122,7 +121,7 @@ mkdir -p out
|
|||||||
|
|
||||||
source ${ORIG_DIR}/venv/bin/activate
|
source ${ORIG_DIR}/venv/bin/activate
|
||||||
|
|
||||||
if [[ "$os_name" == "Darwin" ]]; then
|
if [[ "$OS_NAME" == "Darwin" ]]; then
|
||||||
LOCAL_LDFLAGS="-L/opt/homebrew/opt/llvm@${LLVM_VERSION}/lib"
|
LOCAL_LDFLAGS="-L/opt/homebrew/opt/llvm@${LLVM_VERSION}/lib"
|
||||||
LOCAL_CPPFLAGS="-I/opt/homebrew/opt/llvm@${LLVM_VERSION}/include -I/opt/homebrew/include"
|
LOCAL_CPPFLAGS="-I/opt/homebrew/opt/llvm@${LLVM_VERSION}/include -I/opt/homebrew/include"
|
||||||
LOCAL_PATH=${PATH}:/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin
|
LOCAL_PATH=${PATH}:/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin
|
||||||
|
|||||||