Compare commits

..
Author SHA1 Message Date
bridgewaterrobbie 9a74936103 Update Gitignore to ignore generated files. 2025-04-22 14:23:31 -04:00
214 changed files with 2350 additions and 14979 deletions
-7
View File
@@ -1,7 +0,0 @@
name: 'Set up dependency versions'
runs:
using: "composite"
steps:
- name: Set up dependency versions
shell: bash
run: cat ./build/common/versions >> $GITHUB_ENV
-38
View File
@@ -1,38 +0,0 @@
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
View File
@@ -1,23 +0,0 @@
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
View File
@@ -16,9 +16,6 @@ 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
View File
@@ -14,9 +14,6 @@ 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
View File
@@ -14,9 +14,6 @@ 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
View File
@@ -14,9 +14,6 @@ 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
+39 -41
View File
@@ -9,32 +9,22 @@ on:
- main - main
jobs: jobs:
build-desktop-mac: build-desktop:
name: build-mac name: build-desktop
runs-on: macos-14-xlarge runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4.1.6 strategy:
with: matrix:
fetch-depth: 0 os: [macos-14-xlarge, ubuntu-22.04-16core]
- uses: ./.github/actions/mac-prereq
- name: Run build script
run: |
cd build/mac && 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: steps:
- 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
- name: Run build script - name: Run build script
run: | run: |
cd build/linux && printf "y" | ./build.sh presubmit WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
cd build/$WORKFLOW_OS && 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
@@ -45,8 +35,6 @@ 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
@@ -60,7 +48,6 @@ 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'
@@ -79,7 +66,6 @@ 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
@@ -93,9 +79,6 @@ 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
@@ -118,20 +101,30 @@ 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:
fetch-depth: 0 python-version: '3.x'
- 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: mesa path: |
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }} $HOME/Library/Caches/Homebrew
mesa
key: ${{ runner.os }}-mesa-deps-${{ vars.MESA_VERSION }}
- name: Get Mesa - name: Get Mesa
id: mesa-prereq id: mesa-prereq
run: bash test/utils/get_mesa.sh env:
MESA_VERSION: ${{ vars.MESA_VERSION }}
run: |
bash test/utils/get_mesa.sh
- name: Run Test - name: Run Test
run: bash test/renderdiff/test.sh run: |
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
@@ -140,13 +133,11 @@ 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: ./build.sh -W debug test_filamat filament run: source ./build/linux/ci-common.sh && ./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*
@@ -157,16 +148,23 @@ 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: Set up Homebrew
- name: Install clang-tidy and deps 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: Install prerequisites
run: | run: |
pip install pyyaml pip install pyyaml
brew install llvm@${GITHUB_LLVM_VERSION} brew install llvm
sudo ln -s "$(brew --prefix llvm)@${GITHUB_LLVM_VERSION}/bin/clang-tidy" "/usr/local/bin/clang-tidy" sudo ln -s "$(brew --prefix llvm)/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: bash test/code-correctness/test.sh run: |
bash test/code-correctness/test.sh
+6 -42
View File
@@ -29,42 +29,8 @@ on:
types: [created] types: [created]
jobs: jobs:
build-linux: build-desktop:
name: build-linux name: build-desktop
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'
@@ -83,14 +49,15 @@ 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: |
cd build/mac && printf "y" | ./build.sh release WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
cd build/$WORKFLOW_OS && printf "y" | ./build.sh release
cd ../.. cd ../..
mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
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 }}
@@ -117,7 +84,6 @@ 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 }}
@@ -155,7 +121,6 @@ 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 }}
@@ -206,7 +171,6 @@ 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
View File
@@ -14,9 +14,6 @@ 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
+15
View File
@@ -18,3 +18,18 @@ test*.json
results results
/compile_commands.json /compile_commands.json
/.cache /.cache
build/.cmake/
build/CMakeCache.txt
build/CMakeFiles/
build/Makefile
build/SPIRV-Tools*
build/cmake_install.cmake
build/compile_commands.json
build/filament/
build/include/
build/libs/
build/mac/ninja
build/samples/
build/shaders/
build/third_party/
build/tools/
-2
View File
@@ -7,5 +7,3 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut ## Release notes for next branch cut
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
} }
dependencies { dependencies {
implementation 'com.google.android.filament:filament-android:1.59.4' implementation 'com.google.android.filament:filament-android:1.59.3'
} }
``` ```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release: iOS projects can use CocoaPods to install the latest release:
```shell ```shell
pod 'Filament', '~> 1.59.4' pod 'Filament', '~> 1.59.3'
``` ```
## Documentation ## Documentation
-3
View File
@@ -7,9 +7,6 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md). [NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.59.5
## v1.59.4 ## v1.59.4
@@ -1980,7 +1980,7 @@ public class View {
} }
/** /**
* reconstruction filter width typically between 1 (sharper) and 2 (smoother) * reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
*/ */
public float filterWidth = 1.0f; public float filterWidth = 1.0f;
/** /**
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament GROUP=com.google.android.filament
VERSION_NAME=1.59.4 VERSION_NAME=1.59.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android. POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+14 -11
View File
@@ -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,27 +30,30 @@ 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 1 exit 0
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=${GITHUB_NDK_VERSION:-27.0.11718014} FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
(! 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
View File
@@ -0,0 +1 @@
27.0.11718014
+2 -8
View File
@@ -56,16 +56,10 @@ popd >/dev/null
rm -rf out/check-headers rm -rf out/check-headers
mkdir -p out/check-headers mkdir -p out/check-headers
TMP_FILE=out/check-headers/temp.cpp
echo "Checking that public headers compile independently..." echo "Checking that public headers compile independently..."
for include in "${includes[@]}"; do for include in "${includes[@]}"; do
rm -f ${TMP_FILE}
echo "Checking ${include}" echo "Checking ${include}"
if [[ "${include}" == "utils/Systrace.h" ]]; then echo "#include <${include}>" >> out/check-headers/temp.cpp
# A necessary define before we can include utils/Systrace.h clang -std=c++17 -I "${FILAMENT_HEADERS}" out/check-headers/temp.cpp -c -o /dev/null
echo "#define SYSTRACE_TAG SYSTRACE_TAG_DISABLED" >> ${TMP_FILE}
fi
echo "#include <${include}>" >> ${TMP_FILE}
clang -std=c++17 -I "${FILAMENT_HEADERS}" ${TMP_FILE} -c -o /dev/null
done done
echo "Done!" echo "Done!"
+1
View File
@@ -2,4 +2,5 @@
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
View File
@@ -1,18 +0,0 @@
#!/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
View File
@@ -1,6 +0,0 @@
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
+2
View File
@@ -28,6 +28,7 @@ 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
@@ -40,3 +41,4 @@ 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
+6
View File
@@ -0,0 +1,6 @@
#!/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"
+1
View File
@@ -32,6 +32,7 @@ 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
+38
View File
@@ -0,0 +1,38 @@
#!/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
+1
View File
@@ -28,6 +28,7 @@ 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
+8
View File
@@ -0,0 +1,8 @@
#!/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"
+2 -8
View File
@@ -31,16 +31,10 @@ 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}/common/versions" VERSIONS_STR) file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR}) string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
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)
+2 -8
View File
@@ -32,16 +32,10 @@ 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}/common/versions" VERSIONS_STR) file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR}) string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
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)
+2 -8
View File
@@ -31,16 +31,10 @@ 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}/common/versions" VERSIONS_STR) file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR}) string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
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)
+2 -8
View File
@@ -31,16 +31,10 @@ 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}/common/versions" VERSIONS_STR) file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR}) string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
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)
+12
View File
@@ -1,4 +1,16 @@
#!/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
+1 -1
View File
File diff suppressed because one or more lines are too long
+20 -37
View File
@@ -166,7 +166,7 @@ This document is part of the <a href="https://github.com/google/filament">Filame
</p><ul> </p><ul>
<li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a> <li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a>
</li> </li>
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://bsky.app/profile/pixelflinger.bsky.social">@pixelflinger</a></li></ul> <li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://twitter.com/darthmoosious">@darthmoosious</a></li></ul>
<p></p> <p></p>
<a class="target" name="overview">&nbsp;</a><a class="target" name="overview">&nbsp;</a><a class="target" name="toc2">&nbsp;</a><h1>Overview</h1> <a class="target" name="overview">&nbsp;</a><a class="target" name="overview">&nbsp;</a><a class="target" name="toc2">&nbsp;</a><h1>Overview</h1>
@@ -259,27 +259,26 @@ in <a href="#table_standardproperties">table&nbsp;1</a>.
</p><div class="table"> </p><div class="table">
<table class="table"><tbody><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr> <table class="table"><tbody><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr>
<tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">shadowStrength</strong> </td><td style="text-align:left"> Strength factor between 0 and 1 for all shadows received by this material </td></tr> <tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
</tbody></table><center><div class="tablecaption"><a class="target" name="table_standardproperties">&nbsp;</a><b style="font-style:normal;">Table&nbsp;1:</b> Properties of the standard model</div></center></div> </tbody></table><center><div class="tablecaption"><a class="target" name="table_standardproperties">&nbsp;</a><b style="font-style:normal;">Table&nbsp;1:</b> Properties of the standard model</div></center></div>
<p></p><p> <p></p><p>
@@ -1487,13 +1486,10 @@ non-shader data.
</p><dl><dt>Type</dt><dd><p> array of parameter objects </p><dl><dt>Type</dt><dd><p> array of parameter objects
</p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The </p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be name must be a valid GLSL identifier. Entries also have an optional <code>precision</code>, which can be
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
<a href="#table_materialparamstypes">table&nbsp;14</a>. For Android external textures, entries also have an optional <a href="#table_materialparamstypes">table&nbsp;14</a>.
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
</p></dd></dl><div class="table"> </p></dd></dl><div class="table">
<table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr> <table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
@@ -1756,13 +1752,7 @@ non-shader data.
when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document
for more information on how to access these attributes from the shaders. for more information on how to access these attributes from the shaders.
</p></dd></dl><div class="admonition note"><div class="admonition-title"> Interaction with custom variables</div> </p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<p></p><p>
When the <code>color</code> attribute is specified, only four custom variables are available instead of five.</p></div>
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> parameters : [</span> <span class="line"> parameters : [</span>
<span class="line"> {</span> <span class="line"> {</span>
<span class="line"> type : sampler2d,</span> <span class="line"> type : sampler2d,</span>
@@ -1789,7 +1779,7 @@ non-shader data.
</p><dl><dt>Type</dt><dd><p> array of <code>string</code> </p><dl><dt>Type</dt><dd><p> array of <code>string</code>
</p></dd><dt>Value</dt><dd><p> Up to 5 strings, each must be a valid GLSL identifier. </p></dd><dt>Value</dt><dd><p> Up to 4 strings, each must be a valid GLSL identifier.
</p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader. </p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader.
Each entry of the array defines the name of an interpolant. The full name in the fragment Each entry of the array defines the name of an interpolant. The full name in the fragment
@@ -1804,14 +1794,7 @@ non-shader data.
particular if <code>default</code> is specified the default precision is used is the fragment shader particular if <code>default</code> is specified the default precision is used is the fragment shader
(<code>mediump</code>) and in the vertex shader (<code>highp</code>). (<code>mediump</code>) and in the vertex shader (<code>highp</code>).
</p></dd></dl><div class="admonition warning"><div class="admonition-title"> Interaction with required attributes</div> </p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<p></p><p>
If the <code>color</code> attribute is specified in the <code>required</code> list, then only four variables can be used
instead of five.</p></div>
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> name : Skybox,</span> <span class="line"> name : Skybox,</span>
<span class="line"> parameters : [</span> <span class="line"> parameters : [</span>
<span class="line"> {</span> <span class="line"> {</span>
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16 -16
View File
@@ -49,7 +49,7 @@
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#EntityManager">EntityManager</a></td> <td align="left"><a href="#EntityManager">EntityManager</a></td>
<td align="left">Singleton used for constructing entities in Filament's ECS.</td> <td align="left">Singleton used for constructing entities in Filament&#x27;s ECS.</td>
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#Frustum">Frustum</a></td> <td align="left"><a href="#Frustum">Frustum</a></td>
@@ -89,7 +89,7 @@
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#Renderer">Renderer</a></td> <td align="left"><a href="#Renderer">Renderer</a></td>
<td align="left">Represents the platform's native window.</td> <td align="left">Represents the platform&#x27;s native window.</td>
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#Scene">Scene</a></td> <td align="left"><a href="#Scene">Scene</a></td>
@@ -97,7 +97,7 @@
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#SwapChain">SwapChain</a></td> <td align="left"><a href="#SwapChain">SwapChain</a></td>
<td align="left">Represents the platform's native rendering surface.</td> <td align="left">Represents the platform&#x27;s native rendering surface.</td>
</tr> </tr>
<tr> <tr>
<td align="left"><a href="#Texture">Texture</a></td> <td align="left"><a href="#Texture">Texture</a></td>
@@ -604,11 +604,11 @@
</ul> </ul>
<p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>. <p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>.
TODO: It would be better to expose these as JS numbers rather than as JS objects. TODO: It would be better to expose these as JS numbers rather than as JS objects.
This would also be more consistent with Filament's Java bindings.</p> This would also be more consistent with Filament&#x27;s Java bindings.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
<h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2> <h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2>
<p>Singleton used for constructing entities in Filament's ECS.</p> <p>Singleton used for constructing entities in Filament&#x27;s ECS.</p>
<ul> <ul>
<li><strong>entityManager.create()</strong> <li><strong>entityManager.create()</strong>
<ul> <ul>
@@ -742,7 +742,7 @@ properties.</p>
</ul> </ul>
</li> </li>
</ul> </ul>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p> <p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
<h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2> <h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2>
@@ -780,11 +780,11 @@ properties.</p>
</ul> </ul>
</li> </li>
</ul> </ul>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p> <p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
<h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2> <h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2>
<p>Represents the platform's native window.</p> <p>Represents the platform&#x27;s native window.</p>
<ul> <ul>
<li><strong>renderer.render(swapChain, view)</strong> <li><strong>renderer.render(swapChain, view)</strong>
<ul> <ul>
@@ -803,7 +803,7 @@ properties.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
<h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2> <h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2>
<p>Represents the platform's native rendering surface.</p> <p>Represents the platform&#x27;s native rendering surface.</p>
<p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p> <p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
@@ -847,7 +847,7 @@ properties.</p>
</ul> </ul>
</li> </li>
</ul> </ul>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p> <p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
</div> </div>
<div class='classdoc'> <div class='classdoc'>
<h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2> <h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2>
@@ -944,7 +944,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
<ul> <ul>
<li><strong>assets</strong> <li><strong>assets</strong>
<ul> <ul>
<li>Array of strings containing URL's of required assets.</li> <li>Array of strings containing URL&#x27;s of required assets.</li>
</ul> </ul>
</li> </li>
<li><strong>onDone</strong> <li><strong>onDone</strong>
@@ -954,7 +954,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
</li> </li>
<li><strong>onFetched</strong> <li><strong>onFetched</strong>
<ul> <ul>
<li>optional callback that's invoked after each asset is downloaded.</li> <li>optional callback that&#x27;s invoked after each asset is downloaded.</li>
</ul> </ul>
</li> </li>
</ul> </ul>
@@ -1001,7 +1001,7 @@ useful for compressed textures. For example, some platforms accept ETC and other
<ul> <ul>
<li><strong>assets</strong> <li><strong>assets</strong>
<ul> <ul>
<li>Array of strings containing URL's of required assets.</li> <li>Array of strings containing URL&#x27;s of required assets.</li>
</ul> </ul>
</li> </li>
<li><strong>onready</strong> <li><strong>onready</strong>
@@ -1010,12 +1010,12 @@ useful for compressed textures. For example, some platforms accept ETC and other
</ul> </ul>
</li> </li>
</ul> </ul>
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a <p>All JavaScript clients must call the init function, passing in a list of asset URL&#x27;s and a
callback. This callback gets invoked only after all assets have been downloaded and the Filament callback. This callback gets invoked only after all assets have been downloaded and the Filament
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must WebAssembly module has been loaded. Clients should only pass asset URL&#x27;s that absolutely must
be ready at initialization time. be ready at initialization time.
When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global
object, which contains a mapping from URL's to Uint8Array objects.</p> object, which contains a mapping from URL&#x27;s to Uint8Array objects.</p>
</div> </div>
<div class='funcdoc'> <div class='funcdoc'>
<h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2> <h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2>
Binary file not shown.
Binary file not shown.
+157 -157
View File
@@ -10,7 +10,7 @@
textures.</p> textures.</p>
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the <p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p> <a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the <p>Next you&#x27;ll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
archive that corresponds to your development machine rather than the one for web, and the version archive that corresponds to your development machine rather than the one for web, and the version
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
@@ -19,7 +19,7 @@ out the last available release of <a href="https://www.npmjs.com/package/filamen
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and <p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
produces a binary material package that contains shader code and associated metadata. For more produces a binary material package that contains shader code and associated metadata. For more
information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p> information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it <p>Let&#x27;s try out <code>matc</code>. Create the following file in your favorite text editor and call it
<code>plastic.mat</code>.</p> <code>plastic.mat</code>.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material { <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
name : Lit, name : Lit,
@@ -44,16 +44,16 @@ fragment {
</pre></div> </pre></div>
<p>Next, invoke <code>matc</code> as follows.</p> <p>Next, invoke <code>matc</code> as follows.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>plastic.filamat<span style="color: #BBB"> </span>plastic.mat <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
</pre></div> </pre></div>
<p>You should now have a material archive in your working directory, which we'll use later in the <p>You should now have a material archive in your working directory, which we&#x27;ll use later in the
tutorial.</p> tutorial.</p>
<h2>Bake environment map</h2> <h2>Bake environment map</h2>
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and <p>Next we&#x27;ll use Filament&#x27;s <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p> produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p> <p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>pillars_2k<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>pillars_2k.hdr <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x pillars_2k --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 pillars_2k.hdr
</pre></div> </pre></div>
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as <p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
@@ -61,84 +61,84 @@ well as a text file with spherical harmonics coefficients. You can discard the t
IBL KTX contains these coefficients in its metadata.</p> IBL KTX contains these coefficients in its metadata.</p>
<h2>Create JavaScript</h2> <h2>Create JavaScript</h2>
<p>Next, create <code>redball.js</code> with the following content.</p> <p>Next, create <code>redball.js</code> with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">&#39;pillars_2k&#39;</span>; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">&#39;pillars_2k&#39;</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">&#39;plastic.filamat&#39;</span> <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">&#39;plastic.filamat&#39;</span><span style="color: #bbbbbb"></span>
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>ibl_url,<span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=&gt;<span style="color: #BBB"> </span>{ Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>ibl_url,<span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=&gt;<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer$IndexType; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer$IndexType;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.LightType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.LightManager$Type; <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.LightType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.LightManager$Type;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666">0</span>]; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(canvas); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(canvas);<span style="color: #bbbbbb"></span>
}<span style="color: #BBB"> </span>); }<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{ <span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create()); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>]; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">10000</span>; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">10000</span>;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>vec3.rotateY(eye,<span style="color: #BBB"> </span>eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>radians); <span style="color: #bbbbbb"> </span>vec3.rotateY(eye,<span style="color: #bbbbbb"> </span>eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>radians);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>Fov.VERTICAL); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>Fov.VERTICAL);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
} }<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a <p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
new set of assets. We also added some animation to the camera.</p> new set of assets. We also added some animation to the camera.</p>
<p>Next let's create a material instance from the package that we built at the beginning the tutorial. <p>Next let&#x27;s create a material instance from the package that we built at the beginning the tutorial.
Replace the <strong>create material</strong> comment with the following snippet.</p> Replace the <strong>create material</strong> comment with the following snippet.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(filamat_url); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance(); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>red<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0.8</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>]; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>red<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.8</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>];<span style="color: #bbbbbb"></span>
matinstance.setColor3Parameter(<span style="color: #BA2121">&#39;baseColor&#39;</span>,<span style="color: #BBB"> </span>Filament.RgbType.sRGB,<span style="color: #BBB"> </span>red); matinstance.setColor3Parameter(<span style="color: #BA2121">&#39;baseColor&#39;</span>,<span style="color: #bbbbbb"> </span>Filament.RgbType.sRGB,<span style="color: #bbbbbb"> </span>red);<span style="color: #bbbbbb"></span>
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>,<span style="color: #BBB"> </span><span style="color: #666">0.5</span>); matinstance.setFloatParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.5</span>);<span style="color: #bbbbbb"></span>
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoat&#39;</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>); matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoat&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>);<span style="color: #bbbbbb"></span>
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoatRoughness&#39;</span>,<span style="color: #BBB"> </span><span style="color: #666">0.3</span>); matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoatRoughness&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.3</span>);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code> <p>The next step is to create a renderable for the sphere. To help with this, we&#x27;ll use the <code>IcoSphere</code>
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
three arrays:</p> three arrays:</p>
<ul> <ul>
@@ -147,137 +147,137 @@ three arrays:</p>
as quaternions.</li> as quaternions.</li>
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li> <li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
</ul> </ul>
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create <p>Let&#x27;s go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
sphere</strong> with the following snippet.</p> sphere</strong> with the following snippet.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>renderable<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create(); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>renderable<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
scene.addEntity(renderable); scene.addEntity(renderable);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>icosphere<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.IcoSphere(<span style="color: #666">5</span>); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>icosphere<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.IcoSphere(<span style="color: #666666">5</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder() <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.vertexCount(icosphere.vertices.length<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>) <span style="color: #bbbbbb"> </span>.vertexCount(icosphere.vertices.length<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>) <span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT3,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>) <span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT3,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.SHORT4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>) <span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.SHORT4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.normalized(VertexAttribute.TANGENTS) <span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.TANGENTS)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder() <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.indexCount(icosphere.triangles.length) <span style="color: #bbbbbb"> </span>.indexCount(icosphere.triangles.length)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.bufferType(IndexType.USHORT) <span style="color: #bbbbbb"> </span>.bufferType(IndexType.USHORT)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>icosphere.vertices); vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>icosphere.vertices);<span style="color: #bbbbbb"></span>
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>icosphere.tangents); vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>icosphere.tangents);<span style="color: #bbbbbb"></span>
ib.setBuffer(engine,<span style="color: #BBB"> </span>icosphere.triangles); ib.setBuffer(engine,<span style="color: #bbbbbb"> </span>icosphere.triangles);<span style="color: #bbbbbb"></span>
Filament.RenderableManager.Builder(<span style="color: #666">1</span>) Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>}) <span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinstance) <span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinstance)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span>vb,<span style="color: #BBB"> </span>ib) <span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span>vb,<span style="color: #bbbbbb"> </span>ib)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>renderable); <span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>renderable);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that <p>At this point, the app is rendering a sphere, but it is black so it doesn&#x27;t show up. To prove that
the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we
did in the first tutorial.</p> did in the first tutorial.</p>
<h2>Add lighting</h2> <h2>Add lighting</h2>
<p>In this section we will create some directional light sources, as well as an image-based light (IBL) <p>In this section we will create some directional light sources, as well as an image-based light (IBL)
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
lights</strong> comment with the following snippet.</p> lights</strong> comment with the following snippet.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sunlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create(); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sunlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
scene.addEntity(sunlight); scene.addEntity(sunlight);<span style="color: #bbbbbb"></span>
Filament.LightManager.Builder(LightType.SUN) Filament.LightManager.Builder(LightType.SUN)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.color([<span style="color: #666">0.98</span>,<span style="color: #BBB"> </span><span style="color: #666">0.92</span>,<span style="color: #BBB"> </span><span style="color: #666">0.89</span>]) <span style="color: #bbbbbb"> </span>.color([<span style="color: #666666">0.98</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.92</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.89</span>])<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">110000.0</span>) <span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">110000.0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.direction([<span style="color: #666">0.6</span>,<span style="color: #BBB"> </span><span style="color: #666">-1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">-0.8</span>]) <span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">0.6</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-0.8</span>])<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.sunAngularRadius(<span style="color: #666">1.9</span>) <span style="color: #bbbbbb"> </span>.sunAngularRadius(<span style="color: #666666">1.9</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.sunHaloSize(<span style="color: #666">10.0</span>) <span style="color: #bbbbbb"> </span>.sunHaloSize(<span style="color: #666666">10.0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.sunHaloFalloff(<span style="color: #666">80.0</span>) <span style="color: #bbbbbb"> </span>.sunHaloFalloff(<span style="color: #666666">80.0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>sunlight); <span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>sunlight);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>backlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create(); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>backlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
scene.addEntity(backlight); scene.addEntity(backlight);<span style="color: #bbbbbb"></span>
Filament.LightManager.Builder(LightType.DIRECTIONAL) Filament.LightManager.Builder(LightType.DIRECTIONAL)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.direction([<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]) <span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>])<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>) <span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>backlight); <span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>backlight);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra <p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
parameters because Filament will automatically draw a disk into the skybox.</p> parameters because Filament will automatically draw a disk into the skybox.</p>
<p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the <p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the
following (don't type this out, there's an easier way).</p> following (don&#x27;t type this out, there&#x27;s an easier way).</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>format<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataFormat.RGB; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>format<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataFormat.RGB;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>datatype<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>datatype<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV;<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span> <span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[ibl_url]); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[ibl_url]);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>iblktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(ibl_package); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>iblktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(ibl_package);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibltex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder() <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibltex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.width(iblktx.info().pixelWidth) <span style="color: #bbbbbb"> </span>.width(iblktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.height(iblktx.info().pixelHeight) <span style="color: #bbbbbb"> </span>.height(iblktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.levels(iblktx.getNumMipLevels()) <span style="color: #bbbbbb"> </span>.levels(iblktx.getNumMipLevels())<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP) <span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8) <span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">for</span><span style="color: #BBB"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666">&lt;</span><span style="color: #BBB"> </span>iblktx.getNumMipLevels();<span style="color: #BBB"> </span><span style="color: #666">++</span>level)<span style="color: #BBB"> </span>{ <span style="color: #008000; font-weight: bold">for</span><span style="color: #bbbbbb"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666">&lt;</span><span style="color: #bbbbbb"> </span>iblktx.getNumMipLevels();<span style="color: #bbbbbb"> </span><span style="color: #666666">++</span>level)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getCubeBlob(level).getBytes(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getCubeBlob(level).getBytes();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>ibltex.setImageCube(engine,<span style="color: #BBB"> </span>level,<span style="color: #BBB"> </span>pixelbuffer); <span style="color: #bbbbbb"> </span>ibltex.setImageCube(engine,<span style="color: #bbbbbb"> </span>level,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
} }<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span> <span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shstring<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getMetadata(<span style="color: #BA2121">&#39;sh&#39;</span>); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shstring<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getMetadata(<span style="color: #BA2121">&#39;sh&#39;</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shfloats<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #BBB"> </span><span style="color: #666">9</span><span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">3</span>).map(<span style="color: #008000">parseFloat</span>); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shfloats<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">9</span><span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span> <span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndirectLight.Builder() <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndirectLight.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.reflections(ibltex) <span style="color: #bbbbbb"> </span>.reflections(ibltex)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.irradianceSh(<span style="color: #666">3</span>,<span style="color: #BBB"> </span>shfloats) <span style="color: #bbbbbb"> </span>.irradianceSh(<span style="color: #666666">3</span>,<span style="color: #bbbbbb"> </span>shfloats)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>) <span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
scene.setIndirectLight(indirectLight); scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Filament provides a JavaScript utility to make this simpler, <p>Filament provides a JavaScript utility to make this simpler,
simply replace the <strong>create IBL</strong> comment with the following snippet.</p> simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createIblFromKtx1(ibl_url); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
indirectLight.setIntensity(<span style="color: #666">50000</span>); indirectLight.setIntensity(<span style="color: #666666">50000</span>);<span style="color: #bbbbbb"></span>
scene.setIndirectLight(indirectLight); scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<h2>Add background</h2> <h2>Add background</h2>
<p>At this point you can run the demo and you should see a red plastic ball against a black background. <p>At this point you can run the demo and you should see a red plastic ball against a black background.
Without a skybox, the reflections on the ball are not representative of its surroundings. Without a skybox, the reflections on the ball are not representative of its surroundings.
Here's one way to create a texture for the skybox:</p> Here&#x27;s one way to create a texture for the skybox:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[sky_url]); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[sky_url]);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skyktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(sky_package); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skyktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(sky_package);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skytex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder() <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skytex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.width(skyktx.info().pixelWidth) <span style="color: #bbbbbb"> </span>.width(skyktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.height(skyktx.info().pixelHeight) <span style="color: #bbbbbb"> </span>.height(skyktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.levels(<span style="color: #666">1</span>) <span style="color: #bbbbbb"> </span>.levels(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP) <span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8) <span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>skyktx.getCubeBlob(<span style="color: #666">0</span>).getBytes(); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>skyktx.getCubeBlob(<span style="color: #666666">0</span>).getBytes();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
skytex.setImageCube(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>pixelbuffer); skytex.setImageCube(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Filament provides a Javascript utility to make this easier. <p>Filament provides a Javascript utility to make this easier.
Replace <strong>create skybox</strong> with the following.</p> Replace <strong>create skybox</strong> with the following.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSkyFromKtx1(sky_url); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSkyFromKtx1(sky_url);<span style="color: #bbbbbb"></span>
scene.setSkybox(skybox); scene.setSkybox(skybox);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is <p>That&#x27;s it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
available <a href="tutorial_redball.js">here</a>.</p> available <a href="tutorial_redball.js">here</a>.</p>
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p> <p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we&#x27;ll take a closer look at textures and interaction.</p>
</body> </body>
</html> </html>
+121 -121
View File
@@ -8,58 +8,58 @@
<div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">&#x1F517;</a></div> <div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">&#x1F517;</a></div>
<p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed <p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed
textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p> textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p>
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you'll need to use the command-line tools that can be found in <p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you&#x27;ll need to use the command-line tools that can be found in
the appropriate <a href="//github.com/google/filament/releases">Filament release</a> for your development machine. In addition to <code>matc</code> and <code>cmgen</code>, the appropriate <a href="//github.com/google/filament/releases">Filament release</a> for your development machine. In addition to <code>matc</code> and <code>cmgen</code>,
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p> we&#x27;ll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
<h2>Create filamesh file</h2> <h2>Create filamesh file</h2>
<p>Filament does not have an asset loading system, but it does provide a binary mesh format <p>Filament does not have an asset loading system, but it does provide a binary mesh format
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by called <code>filamesh</code> for simple use cases. Let&#x27;s create a compressed filamesh file for suzanne by
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p> converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh<span style="color: #BBB"> </span>--compress<span style="color: #BBB"> </span>monkey.obj<span style="color: #BBB"> </span>suzanne.filamesh <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh --compress monkey.obj suzanne.filamesh
</pre></div> </pre></div>
<h2>Create mipmapped textures</h2> <h2>Create mipmapped textures</h2>
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and <p>Next, let&#x27;s create mipmapped KTX files using filament&#x27;s <code>mipgen</code> tool. We&#x27;ll create compressed and
non-compressed variants for each texture, since not all platforms support the same compression non-compressed variants for each texture, since not all platforms support the same compression
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p> formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span> <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span>
mipgen<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2 mipgen albedo.png albedo.ktx2
mipgen<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2 mipgen --compression<span style="color: #666666">=</span>uastc albedo.png albedo.ktx2
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span> <span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc_normals<span style="color: #BBB"> </span><span style="color: #AA5D1F; font-weight: bold">\</span> mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>uastc_normals <span style="color: #AA5D1F; font-weight: bold">\</span>
<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx2 normal.png normal.ktx2
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span> <span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx mipgen --grayscale roughness.png roughness.ktx
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx2 mipgen --grayscale --compression<span style="color: #666666">=</span>uastc roughness.png roughness.ktx2
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span> <span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx mipgen --grayscale metallic.png metallic.ktx
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx2 mipgen --grayscale --compression<span style="color: #666666">=</span>uastc metallic.png metallic.ktx2
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span> <span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx mipgen --grayscale ao.png ao.ktx
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx2 mipgen --grayscale --compression<span style="color: #666666">=</span>uastc ao.png ao.ktx2
</pre></div> </pre></div>
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p> <p>For more information on mipgen&#x27;s arguments and supported formats, do <code>mipgen --help</code>.</p>
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p> <p>In a production setting, you&#x27;d want to invoke these commands with a script or build system.</p>
<h2>Bake environment map</h2> <h2>Bake environment map</h2>
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p> <p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament&#x27;s <code>cmgen</code> tool to produce cubemap files.</p>
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/venetian_crossroads_2k.hdr">venetian_crossroads_2k.hdr</a>, then invoke the following commands in your terminal.</p> <p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/venetian_crossroads_2k.hdr">venetian_crossroads_2k.hdr</a>, then invoke the following commands in your terminal.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=64</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=64</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
<span style="color: #008000">cd</span><span style="color: #BBB"> </span>venetian*<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span>mv<span style="color: #BBB"> </span>venetian*_ibl.ktx<span style="color: #BBB"> </span>venetian_crossroads_2k_skybox_tiny.ktx<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span><span style="color: #008000">cd</span><span style="color: #BBB"> </span>- <span style="color: #008000">cd</span> venetian* ; mv venetian*_ibl.ktx venetian_crossroads_2k_skybox_tiny.ktx ; <span style="color: #008000">cd</span> -
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
</pre></div> </pre></div>
<h2>Define textured material</h2> <h2>Define textured material</h2>
<p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this <p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this
demo, we'll create a material that uses textures for several parameters.</p> demo, we&#x27;ll create a material that uses textures for several parameters.</p>
<p>Create the following text file and call it <code>textured.mat</code>. Note that our material definition now <p>Create the following text file and call it <code>textured.mat</code>. Note that our material definition now
requires a <code>uv0</code> attribute.</p> requires a <code>uv0</code> attribute.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material { <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
@@ -90,7 +90,7 @@ fragment {
</pre></div> </pre></div>
<p>Next, invoke <code>matc</code> as follows.</p> <p>Next, invoke <code>matc</code> as follows.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>textured.filamat<span style="color: #BBB"> </span>textured.mat <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o textured.filamat textured.mat
</pre></div> </pre></div>
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal <p>You should now have a material archive in your working directory. For the suzanne asset, the normal
@@ -100,65 +100,65 @@ materials, consult the official document describing the <a href="https://google.
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous <p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
tutorial</a>. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code> tutorial</a>. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code>
with the following content.</p> with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span> <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span><span style="color: #bbbbbb"></span>
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>filamesh_url,<span style="color: #BBB"> </span>sky_small_url,<span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=&gt;<span style="color: #BBB"> </span>{ Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>filamesh_url,<span style="color: #bbbbbb"> </span>sky_small_url,<span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=&gt;<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666">0</span>]); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>]);<span style="color: #bbbbbb"></span>
}); });<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{ <span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>filamesh.renderable; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>filamesh.renderable;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create()); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>]; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize(); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov,<span style="color: #BBB"> </span>fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">&lt;</span><span style="color: #BBB"> </span><span style="color: #666">1</span><span style="color: #BBB"> </span><span style="color: #666">?</span><span style="color: #BBB"> </span>Fov.HORIZONTAL<span style="color: #BBB"> </span><span style="color: #666">:</span><span style="color: #BBB"> </span>Fov.VERTICAL; <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov,<span style="color: #bbbbbb"> </span>fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">&lt;</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1</span><span style="color: #bbbbbb"> </span><span style="color: #666666">?</span><span style="color: #bbbbbb"> </span>Fov.HORIZONTAL<span style="color: #bbbbbb"> </span><span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>Fov.VERTICAL;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>fov); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>fov);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
} }<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download <p>Our app will only require a subset of assets to be present for <code>App</code> construction. We&#x27;ll download
the other assets after construction. By using a progressive loading strategy, we can reduce the the other assets after construction. By using a progressive loading strategy, we can reduce the
perceived load time.</p> perceived load time.</p>
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different <p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
@@ -171,85 +171,85 @@ string -- which might be empty.</p>
<p>In our case, we know that our web server will have <code>astc</code> and <code>s3tc</code> variants for albedo, and <code>etc</code> <p>In our case, we know that our web server will have <code>astc</code> and <code>s3tc</code> variants for albedo, and <code>etc</code>
variants for the other textures. The uncompressed variants (empty string) are always available as a variants for the other textures. The uncompressed variants (empty string) are always available as a
last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p> last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;astc s3tc_srgb&#39;</span>); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;astc s3tc_srgb&#39;</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>texture_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;etc&#39;</span>); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>texture_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;etc&#39;</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">&#39;venetian_crossroads_2k&#39;</span> <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">&#39;venetian_crossroads_2k&#39;</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_small_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_small_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_large_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_large_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">&#39;textured.filamat&#39;</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">&#39;textured.filamat&#39;</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">&#39;suzanne.filamesh&#39;</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">&#39;suzanne.filamesh&#39;</span>;<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<h2>Create skybox and IBL</h2> <h2>Create skybox and IBL</h2>
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p> <p>Next, let&#x27;s create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox); <span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url); <span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666">100000</span>); <span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666666">100000</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight); <span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished <p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
loading in.</p> loading in.</p>
<h2>Fetch assets asychronously</h2> <h2>Fetch assets asychronously</h2>
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is <p>Next we&#x27;ll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
very similar to <code>Filament.init</code>. It takes a list of asset URLs and a callback function that triggers very similar to <code>Filament.init</code>. It takes a list of asset URLs and a callback function that triggers
when the assets have finished downloading.</p> when the assets have finished downloading.</p>
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll <p>In our callback, we&#x27;ll make several <code>setTextureParameter</code> calls on the material instance, then we&#x27;ll
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
was created in the app constructor.</p> was created in the app constructor.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #BBB"> </span>albedo_url,<span style="color: #BBB"> </span>roughness_url,<span style="color: #BBB"> </span>metallic_url,<span style="color: #BBB"> </span>normal_url,<span style="color: #BBB"> </span>ao_url],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=&gt;<span style="color: #BBB"> </span>{ <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #bbbbbb"> </span>albedo_url,<span style="color: #bbbbbb"> </span>roughness_url,<span style="color: #bbbbbb"> </span>metallic_url,<span style="color: #bbbbbb"> </span>normal_url,<span style="color: #bbbbbb"> </span>ao_url],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=&gt;<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #BBB"> </span>{srgb<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>}); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #bbbbbb"> </span>{srgb<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sampler<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.TextureSampler( <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sampler<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.TextureSampler(<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR, <span style="color: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>Filament.MagFilter.LINEAR, <span style="color: #bbbbbb"> </span>Filament.MagFilter.LINEAR,<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>Filament.WrapMode.CLAMP_TO_EDGE); <span style="color: #bbbbbb"> </span>Filament.WrapMode.CLAMP_TO_EDGE);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;albedo&#39;</span>,<span style="color: #BBB"> </span>albedo,<span style="color: #BBB"> </span>sampler); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;albedo&#39;</span>,<span style="color: #bbbbbb"> </span>albedo,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>,<span style="color: #BBB"> </span>roughness,<span style="color: #BBB"> </span>sampler); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>,<span style="color: #bbbbbb"> </span>roughness,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;metallic&#39;</span>,<span style="color: #BBB"> </span>metallic,<span style="color: #BBB"> </span>sampler); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;metallic&#39;</span>,<span style="color: #bbbbbb"> </span>metallic,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;normal&#39;</span>,<span style="color: #BBB"> </span>normal,<span style="color: #BBB"> </span>sampler); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;normal&#39;</span>,<span style="color: #bbbbbb"> </span>normal,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;ao&#39;</span>,<span style="color: #BBB"> </span>ao,<span style="color: #BBB"> </span>sampler); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;ao&#39;</span>,<span style="color: #bbbbbb"> </span>ao,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
}); });<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<h2>Introduce trackball rotation</h2> <h2>Introduce trackball rotation</h2>
<p>Add the following script tag to your HTML file. This imports a small third-party library that <p>Add the following script tag to your HTML file. This imports a small third-party library that
listens for drag events and computes a rotation matrix.</p> listens for drag events and computes a rotation matrix.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gltumble&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gltumble&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
</pre></div> </pre></div>
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following <p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
two code snippets.</p> two code snippets.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Trackball(canvas,<span style="color: #BBB"> </span>{startSpin<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #666">0.035</span>}); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Trackball(canvas,<span style="color: #bbbbbb"> </span>{startSpin<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0.035</span>});<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager(); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
tcm.setTransform(inst,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix()); tcm.setTransform(inst,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());<span style="color: #bbbbbb"></span>
inst.<span style="color: #A2F; font-weight: bold">delete</span>(); inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available <p>That&#x27;s it, we now have a fast-loading interactive demo. The complete JavaScript file is available
<a href="tutorial_suzanne.js">here</a>.</p> <a href="tutorial_suzanne.js">here</a>.</p>
</body> </body>
+110 -110
View File
@@ -8,30 +8,30 @@
<div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">&#x1F517;</a></div> <div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">&#x1F517;</a></div>
<h2>Literate programming</h2> <h2>Literate programming</h2>
<p>The markdown source for this tutorial is not only used to generate this <p>The markdown source for this tutorial is not only used to generate this
web page, it's also used to generate the JavaScript for the above demo. web page, it&#x27;s also used to generate the JavaScript for the above demo.
We use a small Python script for weaving (generating HTML) and tangling We use a small Python script for weaving (generating HTML) and tangling
(generating JS). In the code samples, you'll often see (generating JS). In the code samples, you&#x27;ll often see
<code>// TODO: &lt;some task&gt;</code>. These are special markers that get replaced by <code>// TODO: &lt;some task&gt;</code>. These are special markers that get replaced by
subsequent code blocks.</p> subsequent code blocks.</p>
<h2>Start your project</h2> <h2>Start your project</h2>
<p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates <p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates
a mobile-friendly page with a full-screen canvas.</p> a mobile-friendly page with a full-screen canvas.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500">&lt;!DOCTYPE html&gt;</span> <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500">&lt;!DOCTYPE html&gt;</span>
&lt;<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;en&quot;</span>&gt; &lt;<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;en&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">head</span>&gt; &lt;<span style="color: #008000; font-weight: bold">head</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">title</span>&gt;Filament Tutorial&lt;/<span style="color: #008000; font-weight: bold">title</span>&gt; &lt;<span style="color: #008000; font-weight: bold">title</span>&gt;Filament Tutorial&lt;/<span style="color: #008000; font-weight: bold">title</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;utf-8&quot;</span>&gt; &lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;utf-8&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;viewport&quot;</span> <span style="color: #687822">content</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;width=device-width,user-scalable=no,initial-scale=1&quot;</span>&gt; &lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;viewport&quot;</span> <span style="color: #687822">content</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;width=device-width,user-scalable=no,initial-scale=1&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">style</span>&gt; &lt;<span style="color: #008000; font-weight: bold">style</span>&gt;<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span>touch-action:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span>touch-action:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>&lt;/<span style="color: #008000; font-weight: bold">style</span>&gt; <span style="color: #bbbbbb"> </span>&lt;/<span style="color: #008000; font-weight: bold">style</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">head</span>&gt; &lt;/<span style="color: #008000; font-weight: bold">head</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">body</span>&gt; &lt;<span style="color: #008000; font-weight: bold">body</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">canvas</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">canvas</span>&gt; &lt;<span style="color: #008000; font-weight: bold">canvas</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">canvas</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;filament.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt; &lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;filament.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gl-matrix@2.8.1&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt; &lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gl-matrix@2.8.1&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">&quot;triangle.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt; &lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;triangle.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">body</span>&gt; &lt;/<span style="color: #008000; font-weight: bold">body</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">html</span>&gt; &lt;/<span style="color: #008000; font-weight: bold">html</span>&gt;
</pre></div> </pre></div>
@@ -48,63 +48,63 @@ a mobile-friendly page with a full-screen canvas.</p>
<li><code>triangle.js</code> will contain your application code.</li> <li><code>triangle.js</code> will contain your application code.</li>
</ul> </ul>
<p>Go ahead and create <code>triangle.js</code> with the following content.</p> <p>Go ahead and create <code>triangle.js</code> with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{ <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>); <span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{ <span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>} <span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
} }<span style="color: #bbbbbb"></span>
Filament.init([<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=&gt;<span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App()<span style="color: #BBB"> </span>}<span style="color: #BBB"> </span>); Filament.init([<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=&gt;<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App()<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize <p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
events.</p> events.</p>
<p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</p> <p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</p>
<p>The callback will be triggered only after all assets finish downloading and the Filament module has <p>The callback will be triggered only after all assets finish downloading and the Filament module has
become ready. In our callback, we simply instantiated the <code>App</code> object, since we'll do most of the become ready. In our callback, we simply instantiated the <code>App</code> object, since we&#x27;ll do most of the
work in its constructor. We also set the app instance into a <code>Window</code> property to make it accessible work in its constructor. We also set the app instance into a <code>Window</code> property to make it accessible
from the developer console.</p> from the developer console.</p>
<p>Go ahead and download <a href="triangle.filamat">triangle.filamat</a> and place it in your project folder. <p>Go ahead and download <a href="triangle.filamat">triangle.filamat</a> and place it in your project folder.
This is a <em>material package</em>, which is a binary file that contains shaders and other bits of data This is a <em>material package</em>, which is a binary file that contains shaders and other bits of data
that define a PBR material. We'll learn more about material packages in the next tutorial.</p> that define a PBR material. We&#x27;ll learn more about material packages in the next tutorial.</p>
<h2>Spawn a local server</h2> <h2>Spawn a local server</h2>
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the <p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
file system. One way around this is to create a temporary server using Python or node:</p> file system. One way around this is to create a temporary server using Python or node:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>http.server<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 3</span> <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3 -m http.server <span style="color: #3D7B7B; font-style: italic"># Python 3</span>
python<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>SimpleHTTPServer<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 2.7</span> python -m SimpleHTTPServer <span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
npx<span style="color: #BBB"> </span>http-server<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span><span style="color: #666">8000</span><span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># nodejs</span> npx http-server -p <span style="color: #666666">8000</span> <span style="color: #3D7B7B; font-style: italic"># nodejs</span>
</pre></div> </pre></div>
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you <p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
can load the page without any errors appearing in the developer console.</p> can load the page without any errors appearing in the developer console.</p>
<p>Take care not to use Python's simple server in production since it does not serve WebAssembly files <p>Take care not to use Python&#x27;s simple server in production since it does not serve WebAssembly files
with the correct MIME type.</p> with the correct MIME type.</p>
<h2>Create the Engine and Scene</h2> <h2>Create the Engine and Scene</h2>
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding <p>We now have a basic skeleton that can respond to paint and resize events. Let&#x27;s start adding
Filament objects to the app. Insert the following code into the top of the app constructor.</p> Filament objects to the app. Insert the following code into the top of the app constructor.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666">0</span>]; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the <p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the
canvas in order to create a WebGL 2.0 context in its contructor.</p> canvas in order to create a WebGL 2.0 context in its contructor.</p>
<p>The engine is a factory for many Filament entities, including <code>Scene</code>, which is a flat container of <p>The engine is a factory for many Filament entities, including <code>Scene</code>, which is a flat container of
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the entities. Let&#x27;s go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
scene.</p> scene.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene(); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create(); <span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle); <span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>. <p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
@@ -112,30 +112,30 @@ The triangle entity in the above snippet does not yet have an associated compone
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
calls.</p> calls.</p>
<h2>Construct typed arrays</h2> <h2>Construct typed arrays</h2>
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a <p>Next we&#x27;ll create two typed arrays: a positions array with XY coordinates for each vertex, and a
colors array with a 32-bit word for each vertex.</p> colors array with a 32-bit word for each vertex.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_POSITIONS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Float32Array</span>([ <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Float32Array</span>([<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>, <span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>), <span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>), <span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
]); ]);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_COLORS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666">0xffff0000</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff00ff00</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff0000ff</span>]); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_COLORS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666666">0xffff0000</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff00ff00</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff0000ff</span>]);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p> <p>Next we&#x27;ll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder() <span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.vertexCount(<span style="color: #666">3</span>) <span style="color: #bbbbbb"> </span>.vertexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>) <span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT2,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">8</span>) <span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT2,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">8</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.UBYTE4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>) <span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.UBYTE4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.normalized(VertexAttribute.COLOR) <span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.COLOR)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>TRIANGLE_POSITIONS); <span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>TRIANGLE_COLORS); <span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_COLORS);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using <p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
@@ -147,74 +147,74 @@ self-documenting.</p>
<p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single <p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single
attribute. Alternatively, we could have interleaved or concatenated these attributes into a single attribute. Alternatively, we could have interleaved or concatenated these attributes into a single
buffer slot.</p> buffer slot.</p>
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds <p>Next we&#x27;ll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
the integers 0,1,2.</p> the integers 0,1,2.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder() <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.indexCount(<span style="color: #666">3</span>) <span style="color: #bbbbbb"> </span>.indexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT) <span style="color: #bbbbbb"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine); <span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">2</span>])); <span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">2</span>]));<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has <p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has
one buffer slot, and it can only contain two types of data (USHORT or UINT).</p> one buffer slot, and it can only contain two types of data (USHORT or UINT).</p>
<h2>Finish up initialization</h2> <h2>Finish up initialization</h2>
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the <p>Next let&#x27;s construct an actual <code>Material</code> from the material package that was downloaded (the
material is an object; the package is just a binary blob), then extract the default material is an object; the package is just a binary blob), then extract the default
<code>MaterialInstance</code> from the material object. Material instances have concrete values for their <code>MaterialInstance</code> from the material object. Material instances have concrete values for their
parameters, and they can be bound to renderables. We'll learn more about material instances in the parameters, and they can be bound to renderables. We&#x27;ll learn more about material instances in the
next tutorial.</p> next tutorial.</p>
<p>After extracting the material instance, we can finally create a renderable component for the <p>After extracting the material instance, we can finally create a renderable component for the
triangle by setting up a bounding box and passing in the vertex and index buffers.</p> triangle by setting up a bounding box and passing in the vertex and index buffers.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>mat<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>mat<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat.getDefaultInstance(); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat.getDefaultInstance();<span style="color: #bbbbbb"></span>
Filament.RenderableManager.Builder(<span style="color: #666">1</span>) Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>}) <span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinst) <span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinst)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.ib) <span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.ib)<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle); <span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and <p>Next let&#x27;s wrap up the initialization routine by creating the swap chain, renderer, camera, and
view.</p> view.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain(); <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer(); <span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create()); <span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView(); <span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera); <span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene); <span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span> <span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.1</span>,<span style="color: #BBB"> </span><span style="color: #666">0.2</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>],<span style="color: #BBB"> </span>clear<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>}); <span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.2</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>],<span style="color: #bbbbbb"> </span>clear<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span> <span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.resize(); <span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>At this point, we're done creating all Filament entities, and the code should run without errors. <p>At this point, we&#x27;re done creating all Filament entities, and the code should run without errors.
However the canvas is still blank!</p> However the canvas is still blank!</p>
<h2>Render and resize handlers</h2> <h2>Render and resize handlers</h2>
<p>Recall that our App class has a skeletal render method, which the browser calls every time it needs <p>Recall that our App class has a skeletal render method, which the browser calls every time it needs
to repaint. Often this is 60 times a second.</p> to repaint. Often this is 60 times a second.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #BBB"> </span>{ <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span> <span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render); <span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
} }<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following <p>Let&#x27;s flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
code to the top of the render method.</p> code to the top of the render method.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span> <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">1000</span>; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1000</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>transform<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat4.fromRotation(mat4.create(),<span style="color: #BBB"> </span>radians,<span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>transform<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat4.fromRotation(mat4.create(),<span style="color: #bbbbbb"> </span>radians,<span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager(); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle); <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
tcm.setTransform(inst,<span style="color: #BBB"> </span>transform); tcm.setTransform(inst,<span style="color: #bbbbbb"> </span>transform);<span style="color: #bbbbbb"></span>
inst.<span style="color: #A2F; font-weight: bold">delete</span>(); inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span> <span style="color: #3D7B7B; font-style: italic">// Render the frame.</span><span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view); <span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>The first half of our render method obtains the transform component of the triangle entity and uses <p>The first half of our render method obtains the transform component of the triangle entity and uses
@@ -225,19 +225,19 @@ that it wants to skip a frame, hence the <code>if</code> statement.</p>
<p>One last step. Add the following code to the resize method. This adjusts the resolution of the <p>One last step. Add the following code to the resize method. This adjusts the resolution of the
rendering surface when the window size changes, taking <code>devicePixelRatio</code> into account for high-DPI rendering surface when the window size changes, taking <code>devicePixelRatio</code> into account for high-DPI
displays. It also adjusts the camera frustum accordingly.</p> displays. It also adjusts the camera frustum accordingly.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio; <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]); <span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Projection<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Projection; <span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Projection<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Projection;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #BBB"> </span><span style="color: #666">-</span>aspect,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>); <span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #bbbbbb"> </span><span style="color: #666666">-</span>aspect,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>);<span style="color: #bbbbbb"></span>
</pre></div> </pre></div>
<p>You should now have a spinning triangle! The completed JavaScript is available <p>You should now have a spinning triangle! The completed JavaScript is available
<a href="tutorial_triangle.js">here</a>.</p> <a href="tutorial_triangle.js">here</a>.</p>
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p> <p>In the <a href="tutorial_redball.html">next tutorial</a>, we&#x27;ll take a closer look at Filament materials and 3D rendering.</p>
</body> </body>
</html> </html>
-24
View File
@@ -5,18 +5,6 @@ set(TARGET backend)
set(PUBLIC_HDR_DIR include) set(PUBLIC_HDR_DIR include)
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR}) set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
# ==================================================================================================
# Compilation options
# ==================================================================================================
#
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
set(BACKEND_SANITIZERS)
if (BACKEND_SANITIZATION STREQUAL "ASAN")
set(BACKEND_SANITIZERS -fsanitize=address)
endif()
# ================================================================================================== # ==================================================================================================
# Sources and headers # Sources and headers
# ================================================================================================== # ==================================================================================================
@@ -206,8 +194,6 @@ if (FILAMENT_SUPPORTS_VULKAN)
src/vulkan/VulkanDriver.cpp src/vulkan/VulkanDriver.cpp
src/vulkan/VulkanDriver.h src/vulkan/VulkanDriver.h
src/vulkan/VulkanDriverFactory.h src/vulkan/VulkanDriverFactory.h
src/vulkan/VulkanExternalImageManager.cpp
src/vulkan/VulkanExternalImageManager.h
src/vulkan/VulkanFboCache.cpp src/vulkan/VulkanFboCache.cpp
src/vulkan/VulkanFboCache.h src/vulkan/VulkanFboCache.h
src/vulkan/VulkanHandles.cpp src/vulkan/VulkanHandles.cpp
@@ -271,8 +257,6 @@ 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
@@ -484,7 +468,6 @@ target_compile_options(${TARGET} PRIVATE
${OSMESA_COMPILE_FLAGS} ${OSMESA_COMPILE_FLAGS}
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}> $<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}> $<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
${BACKEND_SANITIZERS}
) )
if (FILAMENT_SUPPORTS_METAL) if (FILAMENT_SUPPORTS_METAL)
@@ -495,8 +478,6 @@ if (FILAMENT_SUPPORTS_WEBGPU)
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>) target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
endif() endif()
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(${TARGET} PRIVATE target_link_libraries(${TARGET} PRIVATE
${OSMESA_LINKER_FLAGS} ${OSMESA_LINKER_FLAGS}
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}> $<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
@@ -566,8 +547,6 @@ if (APPLE AND NOT IOS)
test/test_RenderExternalImage.cpp) test/test_RenderExternalImage.cpp)
add_library(backend_test STATIC ${BACKEND_TEST_SRC}) add_library(backend_test STATIC ${BACKEND_TEST_SRC})
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS}) target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
set(BACKEND_TEST_DEPS set(BACKEND_TEST_DEPS
OSDependent OSDependent
@@ -606,7 +585,6 @@ if (APPLE AND NOT IOS)
# linker from removing "unused" symbols. # linker from removing "unused" symbols.
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test) target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests) set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
# This is needed after XCode 15.3 # This is needed after XCode 15.3
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
@@ -616,8 +594,6 @@ endif()
if (LINUX) if (LINUX)
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC}) add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS}) target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests) set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
endif() endif()
@@ -30,7 +30,6 @@
#include <utils/compiler.h> #include <utils/compiler.h>
#include <utils/debug.h> #include <utils/debug.h>
#include <utils/ostream.h> #include <utils/ostream.h>
#include <utils/StaticString.h>
#include <math/vec4.h> #include <math/vec4.h>
@@ -1140,7 +1139,6 @@ struct ExternalSamplerDatum {
static_assert(sizeof(ExternalSamplerDatum) == 12); static_assert(sizeof(ExternalSamplerDatum) == 12);
struct DescriptorSetLayout { struct DescriptorSetLayout {
std::variant<utils::StaticString, utils::CString, std::monostate> label;
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings; utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
// TODO: uncomment when needed // TODO: uncomment when needed
@@ -1457,11 +1455,6 @@ enum class Workaround : uint16_t {
DISABLE_BLIT_INTO_TEXTURE_ARRAY, DISABLE_BLIT_INTO_TEXTURE_ARRAY,
// Multiple workarounds needed for PowerVR GPUs // Multiple workarounds needed for PowerVR GPUs
POWER_VR_SHADER_WORKAROUNDS, POWER_VR_SHADER_WORKAROUNDS,
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
// creating programs for the default material, leading to startup stutters. This workaround
// prevents these stutters by not precaching depth variants of the default material for those
// particular browsers.
DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL,
}; };
using StereoscopicType = backend::Platform::StereoscopicType; using StereoscopicType = backend::Platform::StereoscopicType;
+2 -2
View File
@@ -44,8 +44,8 @@ public:
struct Descriptor { struct Descriptor {
utils::CString name; utils::CString name;
DescriptorType type; backend::DescriptorType type;
descriptor_binding_t binding; backend::descriptor_binding_t binding;
}; };
struct SpecializationConstant { struct SpecializationConstant {
@@ -294,16 +294,6 @@ public:
VkQueue getProtectedGraphicsQueue() const noexcept; VkQueue getProtectedGraphicsQueue() const noexcept;
struct ExternalImageMetadata { struct ExternalImageMetadata {
/**
* The Filament texture format.
*/
TextureFormat filamentFormat;
/**
* The Filament texture usage.
*/
TextureUsage filamentUsage;
/** /**
* The width of the external image * The width of the external image
*/ */
@@ -314,6 +304,11 @@ public:
*/ */
uint32_t height; uint32_t height;
/**
* The layerCount of the external image
*/
uint32_t layerCount;
/** /**
* The layer count of the external image * The layer count of the external image
*/ */
@@ -329,6 +324,11 @@ public:
*/ */
VkFormat format; VkFormat format;
/**
* An external buffer can be protected. This tells you if it is.
*/
bool isProtected;
/** /**
* The type of external format (opaque int) if used. * The type of external format (opaque int) if used.
*/ */
@@ -348,61 +348,20 @@ public:
* Heap information * Heap information
*/ */
uint32_t memoryTypeBits; uint32_t memoryTypeBits;
/**
* Ycbcr conversion components
*/
VkComponentMapping ycbcrConversionComponents;
/**
* Ycbcr model
*/
VkSamplerYcbcrModelConversion ycbcrModel;
/**
* Ycbcr range
*/
VkSamplerYcbcrRange ycbcrRange;
/**
* Ycbcr x chroma offset
*/
VkChromaLocation xChromaOffset;
/**
* Ycbcr y chroma offset
*/
VkChromaLocation yChromaOffset;
}; };
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
using ImageData = std::pair<VkImage, VkDeviceMemory>;
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
VkImageUsageFlags usage);
// Note that the image metadata might change per-frame, hence we need a method for extracting virtual VkSampler createExternalSampler(SamplerYcbcrConversion chroma,
// it. SamplerParams sampler, uint32_t internalFormat);
virtual ExternalImageMetadata extractExternalImageMetadata(ExternalImageHandleRef image) const {
return {};
}
struct ImageData { virtual VkImageView createExternalImageView(SamplerYcbcrConversion chroma,
struct Bundle { uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
VkImage image = VK_NULL_HANDLE; VkImageViewType viewType, VkComponentMapping swizzle);
VkDeviceMemory memory = VK_NULL_HANDLE;
inline bool valid() const noexcept {
return image != VK_NULL_HANDLE;
}
};
// It's possible for the external image to also have a known VK format. We need to create an
// image for that in case we are not looking to use an external "sampler" with this image.
Bundle internal;
// If we get a externalFormat in the metadata, then we should create an image with
// VK_FORMAT_UNDEFINED
Bundle external;
};
virtual ImageData createVkImageFromExternal(ExternalImageHandleRef image) const {
return {};
}
protected: protected:
virtual ExtensionSet getSwapchainInstanceExtensions() const; virtual ExtensionSet getSwapchainInstanceExtensions() const;
@@ -415,6 +374,20 @@ private:
// Platform dependent helper methods // Platform dependent helper methods
static ExtensionSet getSwapchainInstanceExtensionsImpl(); static ExtensionSet getSwapchainInstanceExtensionsImpl();
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
VkDevice device);
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
VkDevice device, const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
VkImageUsageFlags usage);
static VkSampler createExternalSamplerImpl(VkDevice device,
SamplerYcbcrConversion chroma, SamplerParams sampler,
uint32_t internalFormat);
static VkImageView createExternalImageViewImpl(VkDevice device,
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
VkImageSubresourceRange range, VkImageViewType viewType,
VkComponentMapping swizzle);
// Platform dependent helper methods // Platform dependent helper methods
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance, static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
uint64_t flags) noexcept; uint64_t flags) noexcept;
@@ -26,7 +26,7 @@ namespace filament::backend {
class VulkanPlatformAndroid : public VulkanPlatform { class VulkanPlatformAndroid : public VulkanPlatform {
public: public:
ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer, Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
bool sRGB) noexcept; bool sRGB) noexcept;
struct UTILS_PUBLIC ExternalImageDescAndroid { struct UTILS_PUBLIC ExternalImageDescAndroid {
@@ -39,26 +39,31 @@ public:
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc( ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
ExternalImageHandleRef externalImage) const noexcept; ExternalImageHandleRef externalImage) const noexcept;
virtual ExternalImageMetadata extractExternalImageMetadata(
ExternalImageHandleRef image) const override;
virtual ImageData createVkImageFromExternal(ExternalImageHandleRef image) const override;
protected: protected:
virtual ExtensionSet getSwapchainInstanceExtensions() const override;
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept override;
private:
struct ExternalImageVulkanAndroid : public Platform::ExternalImage { struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
AHardwareBuffer* aHardwareBuffer = nullptr; AHardwareBuffer* aHardwareBuffer = nullptr;
bool sRGB = false; bool sRGB = false;
unsigned int width; // Texture width
unsigned int height; // Texture height
TextureFormat format;// Texture format
TextureUsage usage; // Texture usage flags
protected: protected:
~ExternalImageVulkanAndroid() override; ~ExternalImageVulkanAndroid() override;
}; };
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
using ImageData = VulkanPlatform::ImageData;
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
VkImageUsageFlags usage);
virtual ExtensionSet getSwapchainInstanceExtensions() const;
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept;
}; };
}// namespace filament::backend }// namespace filament::backend
+2 -2
View File
@@ -84,7 +84,7 @@ void CommandStream::execute(void* buffer) {
Profiler profiler; Profiler profiler;
if (SYSTRACE_TAG) { if constexpr (SYSTRACE_TAG) {
if (UTILS_UNLIKELY(mUsePerformanceCounter)) { if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
// we want to remove all this when tracing is completely disabled // we want to remove all this when tracing is completely disabled
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES); profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
@@ -100,7 +100,7 @@ void CommandStream::execute(void* buffer) {
} }
}); });
if (SYSTRACE_TAG) { if constexpr (SYSTRACE_TAG) {
if (UTILS_UNLIKELY(mUsePerformanceCounter)) { if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
// we want to remove all this when tracing is completely disabled // we want to remove all this when tracing is completely disabled
profiler.stop(); profiler.stop();
+2 -2
View File
@@ -1408,8 +1408,8 @@ void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph, Primit
auto primitive = handle_cast<MetalRenderPrimitive>(rph); auto primitive = handle_cast<MetalRenderPrimitive>(rph);
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh); auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh); auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
primitive->vertexBuffer = vertexBuffer; MetalVertexBufferInfo const* const vbi = handle_cast<MetalVertexBufferInfo>(vertexBuffer->vbih);
primitive->indexBuffer = indexBuffer; primitive->setBuffers(vbi, vertexBuffer, indexBuffer);
primitive->type = pt; primitive->type = pt;
} }
-1
View File
@@ -185,7 +185,6 @@ inline MTLPixelFormat getMetalFormat(PixelDataFormat format, PixelDataType type)
CONVERT(RGBA_INTEGER, UINT, RGBA32Uint); CONVERT(RGBA_INTEGER, UINT, RGBA32Uint);
CONVERT(RGBA_INTEGER, INT, RGBA32Sint); CONVERT(RGBA_INTEGER, INT, RGBA32Sint);
CONVERT(RGBA, FLOAT, RGBA32Float); CONVERT(RGBA, FLOAT, RGBA32Float);
CONVERT(DEPTH_COMPONENT, FLOAT, Depth32Float);
#undef CONVERT #undef CONVERT
return MTLPixelFormatInvalid; return MTLPixelFormatInvalid;
@@ -194,8 +194,12 @@ struct MetalIndexBuffer : public HwIndexBuffer {
}; };
struct MetalRenderPrimitive : public HwRenderPrimitive { struct MetalRenderPrimitive : public HwRenderPrimitive {
MetalRenderPrimitive();
void setBuffers(MetalVertexBufferInfo const* const vbi,
MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer);
// The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak". // The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak".
// The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive. // The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive.
MetalVertexBuffer* vertexBuffer = nullptr; MetalVertexBuffer* vertexBuffer = nullptr;
MetalIndexBuffer* indexBuffer = nullptr; MetalIndexBuffer* indexBuffer = nullptr;
}; };
@@ -376,6 +380,7 @@ public:
math::uint2 getAttachmentSize() noexcept; math::uint2 getAttachmentSize() noexcept;
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
uint8_t getSamples() const { return samples; } uint8_t getSamples() const { return samples; }
Attachment getDrawColorAttachment(size_t index); Attachment getDrawColorAttachment(size_t index);
@@ -536,6 +536,15 @@ MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uin
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount), uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { } buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
MetalRenderPrimitive::MetalRenderPrimitive() {
}
void MetalRenderPrimitive::setBuffers(MetalVertexBufferInfo const* const vbi,
MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer) {
this->vertexBuffer = vertexBuffer;
this->indexBuffer = indexBuffer;
}
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
: HwProgram(program.getName()), mContext(context) { : HwProgram(program.getName()), mContext(context) {
mToken = context.shaderCompiler->createProgram(program.getName(), std::move(program)); mToken = context.shaderCompiler->createProgram(program.getName(), std::move(program));
+37 -29
View File
@@ -16,15 +16,9 @@
#include "GLUtils.h" #include "GLUtils.h"
#include "private/backend/Driver.h"
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/trap.h> #include <utils/trap.h>
#include <string_view> #include "private/backend/Driver.h"
#include <stddef.h>
namespace filament::backend { namespace filament::backend {
@@ -34,31 +28,38 @@ using namespace utils;
namespace GLUtils { namespace GLUtils {
UTILS_NOINLINE UTILS_NOINLINE
std::string_view getGLErrorString(GLenum error) noexcept { const char* getGLError(GLenum error) noexcept {
const char* string = "unknown";
switch (error) { switch (error) {
case GL_NO_ERROR: case GL_NO_ERROR:
return "GL_NO_ERROR"; string = "GL_NO_ERROR";
break;
case GL_INVALID_ENUM: case GL_INVALID_ENUM:
return "GL_INVALID_ENUM"; string = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE: case GL_INVALID_VALUE:
return "GL_INVALID_VALUE"; string = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION: case GL_INVALID_OPERATION:
return "GL_INVALID_OPERATION"; string = "GL_INVALID_OPERATION";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION: case GL_INVALID_FRAMEBUFFER_OPERATION:
return "GL_INVALID_FRAMEBUFFER_OPERATION"; string = "GL_INVALID_FRAMEBUFFER_OPERATION";
break;
case GL_OUT_OF_MEMORY: case GL_OUT_OF_MEMORY:
return "GL_OUT_OF_MEMORY"; string = "GL_OUT_OF_MEMORY";
break;
default: default:
break; break;
} }
return "unknown"; return string;
} }
UTILS_NOINLINE UTILS_NOINLINE
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept { GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const error = glGetError(); GLenum const error = glGetError();
if (UTILS_VERY_UNLIKELY(error != GL_NO_ERROR)) { if (error != GL_NO_ERROR) {
auto const string = getGLErrorString(error); const char* string = getGLError(error);
out << "OpenGL error " << io::hex << error << " (" << string << ") in \"" out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl; << function << "\" at line " << io::dec << line << io::endl;
} }
@@ -68,39 +69,46 @@ GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcep
UTILS_NOINLINE UTILS_NOINLINE
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept { void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const err = checkGLError(out, function, line); GLenum const err = checkGLError(out, function, line);
if (UTILS_VERY_UNLIKELY(err != GL_NO_ERROR)) { if (err != GL_NO_ERROR) {
debug_trap(); debug_trap();
} }
} }
UTILS_NOINLINE UTILS_NOINLINE
std::string_view getFramebufferStatusString(GLenum status) noexcept { const char* getFramebufferStatus(GLenum status) noexcept {
const char* string = "unknown";
switch (status) { switch (status) {
case GL_FRAMEBUFFER_COMPLETE: case GL_FRAMEBUFFER_COMPLETE:
return "GL_FRAMEBUFFER_COMPLETE"; string = "GL_FRAMEBUFFER_COMPLETE";
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; string = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; string = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
break;
case GL_FRAMEBUFFER_UNSUPPORTED: case GL_FRAMEBUFFER_UNSUPPORTED:
return "GL_FRAMEBUFFER_UNSUPPORTED"; string = "GL_FRAMEBUFFER_UNSUPPORTED";
break;
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
case GL_FRAMEBUFFER_UNDEFINED: case GL_FRAMEBUFFER_UNDEFINED:
return "GL_FRAMEBUFFER_UNDEFINED"; string = "GL_FRAMEBUFFER_UNDEFINED";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; string = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
break;
#endif #endif
default: default:
break; break;
} }
return "unknown"; return string;
} }
UTILS_NOINLINE UTILS_NOINLINE
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept { GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = glCheckFramebufferStatus(target); GLenum const status = glCheckFramebufferStatus(target);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) { if (status != GL_FRAMEBUFFER_COMPLETE) {
auto const string = getFramebufferStatusString(status); const char* string = getFramebufferStatus(status);
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \"" out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl; << function << "\" at line " << io::dec << line << io::endl;
} }
@@ -110,7 +118,7 @@ GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* funct
UTILS_NOINLINE UTILS_NOINLINE
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept { void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(out, target, function, line); GLenum const status = checkFramebufferStatus(out, target, function, line);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) { if (status != GL_FRAMEBUFFER_COMPLETE) {
debug_trap(); debug_trap();
} }
} }
+36 -61
View File
@@ -17,26 +17,29 @@
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H #ifndef TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H #define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#include <utils/compiler.h>
#include <utils/debug.h> #include <utils/debug.h>
#include <utils/ostream.h> #include <utils/Log.h>
#include <backend/DriverEnums.h> #include <backend/DriverEnums.h>
#include <string_view> #include <string_view>
#include <unordered_set> #include <unordered_set>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "gl_headers.h" #include "gl_headers.h"
namespace filament::backend::GLUtils { namespace filament::backend {
namespace GLUtils {
std::string_view getGLErrorString(GLenum error) noexcept; const char* getGLError(GLenum error) noexcept;
GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept; GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept; void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
std::string_view getFramebufferStatusString(GLenum err) noexcept; const char* getFramebufferStatus(GLenum err) noexcept;
GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept; GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept; void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
@@ -50,7 +53,7 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char*
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); } # define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
#endif #endif
constexpr GLuint getComponentCount(ElementType const type) noexcept { constexpr GLuint getComponentCount(ElementType type) noexcept {
using ElementType = ElementType; using ElementType = ElementType;
switch (type) { switch (type) {
case ElementType::BYTE: case ElementType::BYTE:
@@ -84,29 +87,27 @@ constexpr GLuint getComponentCount(ElementType const type) noexcept {
case ElementType::USHORT4: case ElementType::USHORT4:
return 4; return 4;
} }
// should never happen
return 1;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Our enums to GLenum conversions // Our enums to GLenum conversions
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags const flags) noexcept { constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
GLbitfield mask = 0; GLbitfield mask = 0;
if (any(flags & TargetBufferFlags::COLOR_ALL)) { if (any(flags & TargetBufferFlags::COLOR_ALL)) {
mask |= GLbitfield(GL_COLOR_BUFFER_BIT); mask |= (GLbitfield)GL_COLOR_BUFFER_BIT;
} }
if (any(flags & TargetBufferFlags::DEPTH)) { if (any(flags & TargetBufferFlags::DEPTH)) {
mask |= GLbitfield(GL_DEPTH_BUFFER_BIT); mask |= (GLbitfield)GL_DEPTH_BUFFER_BIT;
} }
if (any(flags & TargetBufferFlags::STENCIL)) { if (any(flags & TargetBufferFlags::STENCIL)) {
mask |= GLbitfield(GL_STENCIL_BUFFER_BIT); mask |= (GLbitfield)GL_STENCIL_BUFFER_BIT;
} }
return mask; return mask;
} }
constexpr GLenum getBufferUsage(BufferUsage const usage) noexcept { constexpr GLenum getBufferUsage(BufferUsage usage) noexcept {
switch (usage) { switch (usage) {
case BufferUsage::STATIC: case BufferUsage::STATIC:
return GL_STATIC_DRAW; return GL_STATIC_DRAW;
@@ -115,7 +116,7 @@ constexpr GLenum getBufferUsage(BufferUsage const usage) noexcept {
} }
} }
constexpr GLenum getBufferBindingType(BufferObjectBinding const bindingType) noexcept { constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept {
switch (bindingType) { switch (bindingType) {
case BufferObjectBinding::VERTEX: case BufferObjectBinding::VERTEX:
return GL_ARRAY_BUFFER; return GL_ARRAY_BUFFER;
@@ -134,15 +135,13 @@ constexpr GLenum getBufferBindingType(BufferObjectBinding const bindingType) noe
return 0x90D2; // just to return something return 0x90D2; // just to return something
#endif #endif
} }
// should never happen
return GL_ARRAY_BUFFER;
} }
constexpr GLboolean getNormalization(bool const normalized) noexcept { constexpr GLboolean getNormalization(bool normalized) noexcept {
return GLboolean(normalized ? GL_TRUE : GL_FALSE); return GLboolean(normalized ? GL_TRUE : GL_FALSE);
} }
constexpr GLenum getComponentType(ElementType const type) noexcept { constexpr GLenum getComponentType(ElementType type) noexcept {
using ElementType = ElementType; using ElementType = ElementType;
switch (type) { switch (type) {
case ElementType::BYTE: case ElementType::BYTE:
@@ -185,11 +184,9 @@ constexpr GLenum getComponentType(ElementType const type) noexcept {
return GL_HALF_FLOAT_OES; return GL_HALF_FLOAT_OES;
#endif #endif
} }
// should never happen
return GL_INT;
} }
constexpr GLenum getTextureTargetNotExternal(SamplerType const target) noexcept { constexpr GLenum getTextureTargetNotExternal(SamplerType target) noexcept {
switch (target) { switch (target) {
case SamplerType::SAMPLER_2D: case SamplerType::SAMPLER_2D:
return GL_TEXTURE_2D; return GL_TEXTURE_2D;
@@ -205,16 +202,14 @@ constexpr GLenum getTextureTargetNotExternal(SamplerType const target) noexcept
// we should never be here // we should never be here
return GL_TEXTURE_2D; return GL_TEXTURE_2D;
} }
// should never happen
return GL_TEXTURE_2D;
} }
constexpr GLenum getCubemapTarget(uint16_t const layer) noexcept { constexpr GLenum getCubemapTarget(uint16_t layer) noexcept {
assert_invariant(layer <= 5); assert_invariant(layer <= 5);
return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
} }
constexpr GLenum getWrapMode(SamplerWrapMode const mode) noexcept { constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept {
using SamplerWrapMode = SamplerWrapMode; using SamplerWrapMode = SamplerWrapMode;
switch (mode) { switch (mode) {
case SamplerWrapMode::REPEAT: case SamplerWrapMode::REPEAT:
@@ -224,8 +219,6 @@ constexpr GLenum getWrapMode(SamplerWrapMode const mode) noexcept {
case SamplerWrapMode::MIRRORED_REPEAT: case SamplerWrapMode::MIRRORED_REPEAT:
return GL_MIRRORED_REPEAT; return GL_MIRRORED_REPEAT;
} }
// should never happen
return GL_CLAMP_TO_EDGE;
} }
constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept { constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
@@ -241,8 +234,6 @@ constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
return GL_NEAREST_MIPMAP_NEAREST return GL_NEAREST_MIPMAP_NEAREST
- GLenum(SamplerMinFilter::NEAREST_MIPMAP_NEAREST) + GLenum(filter); - GLenum(SamplerMinFilter::NEAREST_MIPMAP_NEAREST) + GLenum(filter);
} }
// should never happen
return GL_NEAREST;
} }
constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept { constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
@@ -250,7 +241,7 @@ constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
} }
constexpr GLenum getBlendEquationMode(BlendEquation const mode) noexcept { constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept {
using BlendEquation = BlendEquation; using BlendEquation = BlendEquation;
switch (mode) { switch (mode) {
case BlendEquation::ADD: return GL_FUNC_ADD; case BlendEquation::ADD: return GL_FUNC_ADD;
@@ -259,11 +250,9 @@ constexpr GLenum getBlendEquationMode(BlendEquation const mode) noexcept {
case BlendEquation::MIN: return GL_MIN; case BlendEquation::MIN: return GL_MIN;
case BlendEquation::MAX: return GL_MAX; case BlendEquation::MAX: return GL_MAX;
} }
// should never happen
return GL_FUNC_ADD;
} }
constexpr GLenum getBlendFunctionMode(BlendFunction const mode) noexcept { constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
using BlendFunction = BlendFunction; using BlendFunction = BlendFunction;
switch (mode) { switch (mode) {
case BlendFunction::ZERO: return GL_ZERO; case BlendFunction::ZERO: return GL_ZERO;
@@ -278,11 +267,9 @@ constexpr GLenum getBlendFunctionMode(BlendFunction const mode) noexcept {
case BlendFunction::ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; case BlendFunction::ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
case BlendFunction::SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; case BlendFunction::SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
} }
// should never happen
return GL_ONE;
} }
constexpr GLenum getCompareFunc(SamplerCompareFunc const func) noexcept { constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept {
switch (func) { switch (func) {
case SamplerCompareFunc::LE: return GL_LEQUAL; case SamplerCompareFunc::LE: return GL_LEQUAL;
case SamplerCompareFunc::GE: return GL_GEQUAL; case SamplerCompareFunc::GE: return GL_GEQUAL;
@@ -293,30 +280,28 @@ constexpr GLenum getCompareFunc(SamplerCompareFunc const func) noexcept {
case SamplerCompareFunc::A: return GL_ALWAYS; case SamplerCompareFunc::A: return GL_ALWAYS;
case SamplerCompareFunc::N: return GL_NEVER; case SamplerCompareFunc::N: return GL_NEVER;
} }
// should never happen
return GL_LEQUAL;
} }
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
constexpr GLenum getTextureCompareMode(SamplerCompareMode const mode) noexcept { constexpr GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept {
return mode == SamplerCompareMode::NONE ? return mode == SamplerCompareMode::NONE ?
GL_NONE : GL_COMPARE_REF_TO_TEXTURE; GL_NONE : GL_COMPARE_REF_TO_TEXTURE;
} }
constexpr GLenum getTextureCompareFunc(SamplerCompareFunc const func) noexcept { constexpr GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func); return getCompareFunc(func);
} }
#endif #endif
constexpr GLenum getDepthFunc(SamplerCompareFunc const func) noexcept { constexpr GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func); return getCompareFunc(func);
} }
constexpr GLenum getStencilFunc(SamplerCompareFunc const func) noexcept { constexpr GLenum getStencilFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func); return getCompareFunc(func);
} }
constexpr GLenum getStencilOp(StencilOperation const op) noexcept { constexpr GLenum getStencilOp(StencilOperation op) noexcept {
switch (op) { switch (op) {
case StencilOperation::KEEP: return GL_KEEP; case StencilOperation::KEEP: return GL_KEEP;
case StencilOperation::ZERO: return GL_ZERO; case StencilOperation::ZERO: return GL_ZERO;
@@ -327,11 +312,9 @@ constexpr GLenum getStencilOp(StencilOperation const op) noexcept {
case StencilOperation::DECR_WRAP: return GL_DECR_WRAP; case StencilOperation::DECR_WRAP: return GL_DECR_WRAP;
case StencilOperation::INVERT: return GL_INVERT; case StencilOperation::INVERT: return GL_INVERT;
} }
// should never happen
return GL_KEEP;
} }
constexpr GLenum getFormat(PixelDataFormat const format) noexcept { constexpr GLenum getFormat(PixelDataFormat format) noexcept {
using PixelDataFormat = PixelDataFormat; using PixelDataFormat = PixelDataFormat;
switch (format) { switch (format) {
case PixelDataFormat::RGB: return GL_RGB; case PixelDataFormat::RGB: return GL_RGB;
@@ -353,11 +336,9 @@ constexpr GLenum getFormat(PixelDataFormat const format) noexcept {
default: return GL_NONE; default: return GL_NONE;
#endif #endif
} }
// should never happen
return GL_RGBA;
} }
constexpr GLenum getType(PixelDataType const type) noexcept { constexpr GLenum getType(PixelDataType type) noexcept {
using PixelDataType = PixelDataType; using PixelDataType = PixelDataType;
switch (type) { switch (type) {
case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE; case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE;
@@ -379,12 +360,10 @@ constexpr GLenum getType(PixelDataType const type) noexcept {
default: return GL_NONE; default: return GL_NONE;
#endif #endif
} }
// should never happen
return GL_UNSIGNED_INT;
} }
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2) #if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
constexpr GLenum getSwizzleChannel(TextureSwizzle const c) noexcept { constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
using TextureSwizzle = TextureSwizzle; using TextureSwizzle = TextureSwizzle;
switch (c) { switch (c) {
case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO; case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO;
@@ -394,12 +373,10 @@ constexpr GLenum getSwizzleChannel(TextureSwizzle const c) noexcept {
case TextureSwizzle::CHANNEL_2: return GL_BLUE; case TextureSwizzle::CHANNEL_2: return GL_BLUE;
case TextureSwizzle::CHANNEL_3: return GL_ALPHA; case TextureSwizzle::CHANNEL_3: return GL_ALPHA;
} }
// should never happen
return GL_RED;
} }
#endif #endif
constexpr GLenum getCullingMode(CullingMode const mode) noexcept { constexpr GLenum getCullingMode(CullingMode mode) noexcept {
switch (mode) { switch (mode) {
case CullingMode::NONE: case CullingMode::NONE:
// should never happen // should never happen
@@ -411,13 +388,11 @@ constexpr GLenum getCullingMode(CullingMode const mode) noexcept {
case CullingMode::FRONT_AND_BACK: case CullingMode::FRONT_AND_BACK:
return GL_FRONT_AND_BACK; return GL_FRONT_AND_BACK;
} }
// should never happen
return GL_FRONT_AND_BACK;
} }
// ES2 supported internal formats for texturing and how they map to a format/type // ES2 supported internal formats for texturing and how they map to a format/type
constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType( constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
TextureFormat const format) noexcept { TextureFormat format) noexcept {
switch (format) { switch (format) {
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE }; case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE }; case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
@@ -438,7 +413,7 @@ constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
// clang loses it on this one, and generates a huge jump table when // clang loses it on this one, and generates a huge jump table when
// inlined. So we don't mark it as inline (only constexpr) which solves the problem, // inlined. So we don't mark it as inline (only constexpr) which solves the problem,
// strangely, when not inlined, clang simply generates an array lookup. // strangely, when not inlined, clang simply generates an array lookup.
constexpr /* inline */ GLenum getInternalFormat(TextureFormat const format) noexcept { constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
switch (format) { switch (format) {
/* Formats supported by our ES2 implementations */ /* Formats supported by our ES2 implementations */
@@ -686,7 +661,7 @@ public:
unordered_string_set split(const char* extensions) noexcept; unordered_string_set split(const char* extensions) noexcept;
} // namespace filament::backend::GLUtils } // namespace GLUtils
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H #endif // TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
+17 -23
View File
@@ -340,7 +340,7 @@ void OpenGLContext::setDefaultState() noexcept {
GL_DITHER, GL_DITHER,
GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_ALPHA_TO_COVERAGE,
GL_SAMPLE_COVERAGE, GL_SAMPLE_COVERAGE,
GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_FILL,
}; };
UTILS_NOUNROLL UTILS_NOUNROLL
@@ -600,12 +600,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
// For Mozilla, the issue appears to be observed regardless of whether the renderer is // For Mozilla, the issue appears to be observed regardless of whether the renderer is
// ANGLE or not. (b/376125497) // ANGLE or not. (b/376125497)
bugs->rebind_buffer_after_deletion = true; bugs->rebind_buffer_after_deletion = true;
// We disable depth precache for the default material on Mozilla FireFox. It struggles with
// slow shader compile/link times if the shader contains large arrays of uniform. Some depth
// program variants have skinning-related data, which incurs this slowness and end up
// causing an initial startup stalls. (b/392917621)
bugs->disable_depth_precache_for_default_material = true;
} }
#ifdef BACKEND_OPENGL_VERSION_GLES #ifdef BACKEND_OPENGL_VERSION_GLES
@@ -1075,41 +1069,41 @@ void OpenGLContext::resetState() noexcept {
glCullFace(state.raster.cullFace); glCullFace(state.raster.cullFace);
glBlendEquationSeparate(state.raster.blendEquationRGB, state.raster.blendEquationA); glBlendEquationSeparate(state.raster.blendEquationRGB, state.raster.blendEquationA);
glBlendFuncSeparate( glBlendFuncSeparate(
state.raster.blendFunctionSrcRGB, state.raster.blendFunctionSrcRGB,
state.raster.blendFunctionDstRGB, state.raster.blendFunctionDstRGB,
state.raster.blendFunctionSrcA, state.raster.blendFunctionSrcA,
state.raster.blendFunctionDstA state.raster.blendFunctionDstA
); );
glColorMask( glColorMask(
state.raster.colorMask, state.raster.colorMask,
state.raster.colorMask, state.raster.colorMask,
state.raster.colorMask, state.raster.colorMask,
state.raster.colorMask state.raster.colorMask
); );
glDepthMask(state.raster.depthMask); glDepthMask(state.raster.depthMask);
glDepthFunc(state.raster.depthFunc); glDepthFunc(state.raster.depthFunc);
// state.stencil // state.stencil
glStencilFuncSeparate( glStencilFuncSeparate(
GL_FRONT, GL_FRONT,
state.stencil.front.func.func, state.stencil.front.func.func,
state.stencil.front.func.ref, state.stencil.front.func.ref,
state.stencil.front.func.mask state.stencil.front.func.mask
); );
glStencilFuncSeparate( glStencilFuncSeparate(
GL_BACK, GL_BACK,
state.stencil.back.func.func, state.stencil.back.func.func,
state.stencil.back.func.ref, state.stencil.back.func.ref,
state.stencil.back.func.mask state.stencil.back.func.mask
); );
glStencilOpSeparate( glStencilOpSeparate(
GL_FRONT, GL_FRONT,
state.stencil.front.op.sfail, state.stencil.front.op.sfail,
state.stencil.front.op.dpfail, state.stencil.front.op.dpfail,
state.stencil.front.op.dppass state.stencil.front.op.dppass
); );
glStencilOpSeparate( glStencilOpSeparate(
GL_BACK, GL_BACK,
state.stencil.back.op.sfail, state.stencil.back.op.sfail,
state.stencil.back.op.dpfail, state.stencil.back.op.dpfail,
state.stencil.back.op.dppass state.stencil.back.op.dppass
@@ -1212,9 +1206,9 @@ void OpenGLContext::resetState() noexcept {
// state.window // state.window
glScissor( glScissor(
state.window.scissor.x, state.window.scissor.x,
state.window.scissor.y, state.window.scissor.y,
state.window.scissor.z, state.window.scissor.z,
state.window.scissor.w state.window.scissor.w
); );
glViewport( glViewport(
@@ -328,11 +328,6 @@ public:
// bugs or performance issues. // bugs or performance issues.
bool force_feature_level0; bool force_feature_level0;
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
// creating programs for the default material, leading to startup stutters. This workaround
// prevents these stutters by not precaching depth variants of the default material for
// those particular browsers.
bool disable_depth_precache_for_default_material;
} bugs = {}; } bugs = {};
@@ -574,9 +569,6 @@ private:
{ bugs.force_feature_level0, { bugs.force_feature_level0,
"force_feature_level0", "force_feature_level0",
""}, ""},
{ bugs.disable_depth_precache_for_default_material,
"disable_depth_precache_for_default_material",
""},
}}; }};
// this is chosen to minimize code size // this is chosen to minimize code size
@@ -2098,7 +2098,6 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer, const m
glstream->user_thread.pending = mPlatform.transformAcquiredImage({ glstream->user_thread.pending = mPlatform.transformAcquiredImage({
hwbuffer, cb, userData, handler }); hwbuffer, cb, userData, handler });
glstream->user_thread.transform = transform;
if (glstream->user_thread.pending.image != nullptr) { if (glstream->user_thread.pending.image != nullptr) {
// If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass // If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass
@@ -2435,8 +2434,6 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
return mContext.bugs.disable_blit_into_texture_array; return mContext.bugs.disable_blit_into_texture_array;
case Workaround::POWER_VR_SHADER_WORKAROUNDS: case Workaround::POWER_VR_SHADER_WORKAROUNDS:
return mContext.bugs.powervr_shader_workarounds; return mContext.bugs.powervr_shader_workarounds;
case Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL:
return mContext.bugs.disable_depth_precache_for_default_material;
default: default:
return false; return false;
} }
@@ -17,10 +17,8 @@
#define COREVIDEO_SILENCE_GL_DEPRECATION #define COREVIDEO_SILENCE_GL_DEPRECATION
#include "CocoaExternalImage.h" #include "CocoaExternalImage.h"
#include "../GLUtils.h"
#include <utils/Panic.h> #include <utils/Panic.h>
#include <utils/Log.h> #include "../GLUtils.h"
namespace filament::backend { namespace filament::backend {
@@ -28,7 +28,6 @@
#include <utils/compiler.h> #include <utils/compiler.h>
#include <utils/Panic.h> #include <utils/Panic.h>
#include <utils/debug.h> #include <utils/debug.h>
#include <utils/Log.h>
namespace filament::backend { namespace filament::backend {
@@ -295,8 +295,6 @@ VulkanCommandBuffer& CommandBufferPool::getRecording() {
} }
void CommandBufferPool::gc() { void CommandBufferPool::gc() {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("CommandBufferPool::gc");
ActiveBuffers reclaimed; ActiveBuffers reclaimed;
mSubmitted.forEachSetBit([this,&reclaimed] (size_t index) { mSubmitted.forEachSetBit([this,&reclaimed] (size_t index) {
auto& buffer = mBuffers[index]; auto& buffer = mBuffers[index];
@@ -306,7 +304,6 @@ void CommandBufferPool::gc() {
} }
}); });
mSubmitted &= ~reclaimed; mSubmitted &= ~reclaimed;
FVK_SYSTRACE_END();
} }
void CommandBufferPool::update() { void CommandBufferPool::update() {
@@ -336,9 +333,7 @@ void CommandBufferPool::wait() {
mSubmitted.forEachSetBit([this, &count, &fences] (size_t index) { mSubmitted.forEachSetBit([this, &count, &fences] (size_t index) {
fences[count++] = mBuffers[index]->getVkFence(); fences[count++] = mBuffers[index]->getVkFence();
}); });
if (count) { vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
}
update(); update();
} }
@@ -152,12 +152,12 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
#elif FVK_ENABLED(FVK_DEBUG_SYSTRACE) #elif FVK_ENABLED(FVK_DEBUG_SYSTRACE)
#include <utils/Systrace.h> #include <utils/Systrace.h>
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT() #define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker) #define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END() #define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
#define FVK_SYSTRACE_SCOPE() SYSTRACE_NAME(__func__) #define FVK_SYSTRACE_SCOPE() SYSTRACE_CALL()
#define FVK_PROFILE_MARKER(marker) FVK_SYSTRACE_SCOPE() #define FVK_PROFILE_MARKER(marker) SYSTRACE_CALL()
#else #else
#define FVK_SYSTRACE_CONTEXT() #define FVK_SYSTRACE_CONTEXT()
@@ -31,8 +31,8 @@ namespace filament::backend {
namespace { namespace {
using DescriptorCount = VulkanDescriptorSetLayout::Count;
using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray; using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
using DescriptorCount = VulkanDescriptorSetCache::DescriptorCount;
// We create a pool for each layout as defined by the number of descriptors of each type. For // We create a pool for each layout as defined by the number of descriptors of each type. For
// example, a layout of // example, a layout of
@@ -203,10 +203,11 @@ public:
DescriptorInfinitePool(VkDevice device) DescriptorInfinitePool(VkDevice device)
: mDevice(device) {} : mDevice(device) {}
VkDescriptorSet obtainSet(DescriptorCount const& count, VkDescriptorSetLayout vklayout) { VkDescriptorSet obtainSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
auto const vklayout = layout->getVkLayout();
DescriptorPool* sameTypePool = nullptr; DescriptorPool* sameTypePool = nullptr;
for (auto& pool: mPools) { for (auto& pool: mPools) {
if (!pool->canAllocate(count)) { if (!pool->canAllocate(layout->count)) {
continue; continue;
} }
if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) { if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) {
@@ -224,7 +225,8 @@ public:
} }
// We need to increase the set of pools by one. // We need to increase the set of pools by one.
mPools.push_back(std::make_unique<DescriptorPool>(mDevice, count, capacity)); mPools.push_back(std::make_unique<DescriptorPool>(mDevice,
DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity));
auto& pool = mPools.back(); auto& pool = mPools.back();
auto ret = pool->obtainSet(vklayout); auto ret = pool->obtainSet(vklayout);
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?"); assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
@@ -274,36 +276,39 @@ void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
} }
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands, void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& useExternalSamplers, VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
fvkutils::DescriptorSetMask const& setMask) {
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the // setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
// actual set of sets that *needs* to be bound. // actual set of sets that *needs* to be bound.
fvkutils::DescriptorSetMask curMask = setMask; fvkutils::DescriptorSetMask curMask = setMask;
auto const& updateSets = mStashedSets; auto& updateSets = mStashedSets;
curMask.forEachSetBit([&](size_t index) { bool const pipelineLayoutIsSame = mLastBoundInfo.pipelineLayout == pipelineLayout;
if (!updateSets[index]) {
curMask.unset(index);
}
});
if (mLastBoundInfo.pipelineLayout == pipelineLayout) { if (pipelineLayoutIsSame) {
auto& lastBoundSets = mLastBoundInfo.boundSets; auto& lastBoundSets = mLastBoundInfo.boundSets;
curMask.forEachSetBit([&](size_t index) { setMask.forEachSetBit([&](size_t index) {
if (updateSets[index] == lastBoundSets[index] && !useExternalSamplers[index]) { if (!updateSets[index] || updateSets[index] == lastBoundSets[index]) {
curMask.unset(index);
}
});
if (curMask.none() &&
mLastBoundInfo.setMask == setMask && mLastBoundInfo.boundSets == updateSets) {
return;
}
} else {
setMask.forEachSetBit([&](size_t index) {
if (!updateSets[index]) {
curMask.unset(index); curMask.unset(index);
} }
}); });
} }
curMask.forEachSetBit([&](size_t index) { curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) {
// This code actually binds the descriptor sets. // This code actually binds the descriptor sets.
auto set = updateSets[index]; auto set = updateSets[index];
VkCommandBuffer const cmdbuffer = commands->buffer(); VkCommandBuffer const cmdbuffer = commands->buffer();
VkDescriptorSet vkset = useExternalSamplers[index] ? set->getExternalSamplerVkSet() :
set->getVkSet();
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index, vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
1, &vkset, set->uniqueDynamicUboCount, set->getOffsets()->data()); 1, &set->getVkSet(), set->uniqueDynamicUboCount, set->getOffsets()->data());
commands->acquire(set); commands->acquire(set);
}); });
@@ -329,7 +334,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
if (set->dynamicUboMask.test(binding)) { if (set->dynamicUboMask.test(binding)) {
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
} }
VkWriteDescriptorSet descriptorWrite = { VkWriteDescriptorSet const descriptorWrite = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = set->getVkSet(), .dstSet = set->getVkSet(),
.dstBinding = binding, .dstBinding = binding,
@@ -338,17 +343,12 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
.pBufferInfo = &info, .pBufferInfo = &info,
}; };
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
if (auto externalSamplerSet = set->getExternalSamplerVkSet();
externalSamplerSet != VK_NULL_HANDLE) {
descriptorWrite.dstSet = externalSamplerSet;
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
}
set->acquire(bufferObject); set->acquire(bufferObject);
} }
void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t binding, void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept { uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
VkSampler sampler) noexcept {
VkImageSubresourceRange range = texture->getPrimaryViewRange(); VkImageSubresourceRange range = texture->getPrimaryViewRange();
VkImageViewType const expectedType = texture->getViewType(); VkImageViewType const expectedType = texture->getViewType();
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) && if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
@@ -364,29 +364,16 @@ void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()), .imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
}; };
VkWriteDescriptorSet descriptorWrite = { VkWriteDescriptorSet const descriptorWrite = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr, .pNext = nullptr,
.dstSet = vkset, .dstSet = set->getVkSet(),
.dstBinding = binding, .dstBinding = binding,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &info, .pImageInfo = &info,
}; };
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
}
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
VkSampler sampler) noexcept {
updateSamplerImpl(set->getVkSet(), binding, texture, sampler);
set->acquire(texture);
}
void VulkanDescriptorSetCache::updateSamplerForExternalSamplerSet(
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
fvkmemory::resource_ptr<VulkanTexture> texture) noexcept {
updateSamplerImpl(set->getExternalSamplerVkSet(), binding, texture, VK_NULL_HANDLE);
set->acquire(texture); set->acquire(texture);
} }
@@ -396,32 +383,32 @@ void VulkanDescriptorSetCache::updateInputAttachment(
// TOOD: fill this in. // TOOD: fill this in.
} }
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet( fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) { Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
auto const vkSet = mDescriptorPool->obtainSet(layout->count, layout->getVkLayout()); auto const vkSet = getVkSet(layout);
auto const& count = layout->count; auto const& count = layout->count;
auto const vklayout = layout->getVkLayout(); auto const vklayout = layout->getVkLayout();
auto set = fvkmemory::resource_ptr<VulkanDescriptorSet>::make( auto set = fvkmemory::resource_ptr<VulkanDescriptorSet>::make(mResourceManager, handle,
mResourceManager, handle, layout->bitmask.dynamicUbo, layout->count.dynamicUbo, layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
[vkSet, count, vklayout, this]( [vkSet, count, vklayout, this](VulkanDescriptorSet*) {
VulkanDescriptorSet*) { this->manualRecycle(count, vklayout, vkSet); }, // Note that mDescriptorPool could be gone due to terminate (when the backend shuts
vkSet); // down).
if (mDescriptorPool) {
mDescriptorPool->recycle(count, vklayout, vkSet);
}
});
set->setVkSet(vkSet);
return set; return set;
} }
VkDescriptorSet VulkanDescriptorSetCache::getVkSet(DescriptorCount const& count, VkDescriptorSet VulkanDescriptorSetCache::getVkSet(
VkDescriptorSetLayout vklayout) { fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
return mDescriptorPool->obtainSet(count, vklayout); return mDescriptorPool->obtainSet(layout);
} }
void VulkanDescriptorSetCache::manualRecycle(VulkanDescriptorSetLayout::Count const& count, void VulkanDescriptorSetCache::manualRecyle(VulkanDescriptorSetLayout::Count const& count,
VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) { VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
// Note that mDescriptorPool could be gone due to terminate (when the backend shuts mDescriptorPool->recycle(count, vklayout, vkSet);
// down).
if (mDescriptorPool) {
mDescriptorPool->recycle(count, vklayout, vkSet);
}
} }
void VulkanDescriptorSetCache::gc() { mStashedSets = {}; } void VulkanDescriptorSetCache::gc() { mStashedSets = {}; }
@@ -43,7 +43,6 @@ public:
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray; using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
using DescriptorSetArray = using DescriptorSetArray =
std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>; std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>;
using DescriptorCount = VulkanDescriptorSetLayout::Count;
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager); VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
~VulkanDescriptorSetCache(); ~VulkanDescriptorSetCache();
@@ -57,10 +56,6 @@ public:
void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding, void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept; fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
void updateSamplerForExternalSamplerSet(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
fvkmemory::resource_ptr<VulkanTexture> texture) noexcept;
void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set, void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
VulkanAttachment const& attachment) noexcept; VulkanAttachment const& attachment) noexcept;
@@ -70,17 +65,17 @@ public:
void unbind(uint8_t setIndex); void unbind(uint8_t setIndex);
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
fvkutils::DescriptorSetMask const& useExternalSamplerMask,
fvkutils::DescriptorSetMask const& setMask); fvkutils::DescriptorSetMask const& setMask);
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout); fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
// This method is meant to be used with external samplers // This method is only meant to be used with external samplers (or internally within this
VkDescriptorSet getVkSet(DescriptorCount const& count, VkDescriptorSetLayout vklayout); // class).
VkDescriptorSet getVkSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
// This method is meant to be used with external samplers // This method is only meant to be used with external samplers.
void manualRecycle(VulkanDescriptorSetLayout::Count const& count, VkDescriptorSetLayout vklayout, void manualRecyle(VulkanDescriptorSetLayout::Count const& count, VkDescriptorSetLayout vklayout,
VkDescriptorSet vkSet); VkDescriptorSet vkSet);
DescriptorSetArray const& getBoundSets() const { return mStashedSets; } DescriptorSetArray const& getBoundSets() const { return mStashedSets; }
@@ -88,9 +83,6 @@ public:
void gc(); void gc();
private: private:
void updateSamplerImpl(VkDescriptorSet set, uint8_t binding,
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
class DescriptorInfinitePool; class DescriptorInfinitePool;
VkDevice mDevice; VkDevice mDevice;
@@ -127,7 +127,6 @@ void VulkanDescriptorSetLayoutCache::terminate() noexcept {
VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout( VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
VulkanDescriptorSetLayout::Bitmask const& bitmasks, VulkanDescriptorSetLayout::Bitmask const& bitmasks,
fvkutils::SamplerBitmask externalSamplers,
utils::FixedCapacityVector<VkSampler> immutableSamplers) { utils::FixedCapacityVector<VkSampler> immutableSamplers) {
LayoutKey key = { LayoutKey key = {
.bitmask = bitmasks, .bitmask = bitmasks,
@@ -142,7 +141,7 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
bitmasks.dynamicUbo); bitmasks.dynamicUbo);
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo); count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo);
count += appendSamplerBindings(&toBind[count], bitmasks.sampler, externalSamplers, count += appendSamplerBindings(&toBind[count], bitmasks.sampler, bitmasks.externalSampler,
immutableSamplers); immutableSamplers);
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
bitmasks.inputAttachment); bitmasks.inputAttachment);
@@ -161,9 +160,9 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout( fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout(
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) { Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) {
BitmaskGroup maskGroup = VulkanDescriptorSetLayout::Bitmask::fromLayoutDescription(info);
auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle, auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle,
std::move(info), getVkLayout(maskGroup, maskGroup.externalSampler)); info);
layout->setVkLayout(getVkLayout(layout->bitmask));
return layout; return layout;
} }
@@ -46,7 +46,6 @@ public:
// This method is meant to be used with external samplers // This method is meant to be used with external samplers
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks, VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
fvkutils::SamplerBitmask externalSamplers,
utils::FixedCapacityVector<VkSampler> immutableSamplers = {}); utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
private: private:
+75 -177
View File
@@ -30,6 +30,7 @@
#include "vulkan/memory/ResourcePointer.h" #include "vulkan/memory/ResourcePointer.h"
#include "vulkan/utils/Conversion.h" #include "vulkan/utils/Conversion.h"
#include "vulkan/utils/Definitions.h" #include "vulkan/utils/Definitions.h"
#include "vulkan/vulkan_core.h"
#include <backend/DriverEnums.h> #include <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatform.h> #include <backend/platforms/VulkanPlatform.h>
@@ -197,9 +198,11 @@ Dispatcher VulkanDriver::getDispatcher() const noexcept {
} }
VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& context, VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
Platform::DriverConfig const& driverConfig) Platform::DriverConfig const& driverConfig) noexcept
: mPlatform(platform), : mPlatform(platform),
mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck, mResourceManager(
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck,
driverConfig.disableHeapHandleTags), driverConfig.disableHeapHandleTags),
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(), mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
mPlatform->getDevice())), mPlatform->getDevice())),
@@ -218,8 +221,6 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager), mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager), mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
mQueryManager(mPlatform->getDevice()), mQueryManager(mPlatform->getDevice()),
mExternalImageManager(platform, &mSamplerCache, &mYcbcrConversionCache, &mDescriptorSetCache,
&mDescriptorSetLayoutCache),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported), mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
mStereoscopicType(driverConfig.stereoscopicType) { mStereoscopicType(driverConfig.stereoscopicType) {
@@ -250,7 +251,7 @@ VulkanDriver::~VulkanDriver() noexcept = default;
UTILS_NOINLINE UTILS_NOINLINE
Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& context, Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& context,
Platform::DriverConfig const& driverConfig) { Platform::DriverConfig const& driverConfig) noexcept {
#if 0 #if 0
// this is useful for development, but too verbose even for debug builds // this is useful for development, but too verbose even for debug builds
// For reference on a 64-bits machine in Release mode: // For reference on a 64-bits machine in Release mode:
@@ -312,7 +313,7 @@ void VulkanDriver::terminate() {
mCurrentSwapChain = {}; mCurrentSwapChain = {};
mDefaultRenderTarget = {}; mDefaultRenderTarget = {};
mPipelineState = {}; mBoundPipeline = {};
mQueryManager.terminate(); mQueryManager.terminate();
@@ -324,10 +325,6 @@ void VulkanDriver::terminate() {
mCommands.terminate(); mCommands.terminate();
// Must come before samplerCache, ycbcrConversionCache, descriptorSetCache,
// descriptorSetLayoutCache
mExternalImageManager.terminate();
mStagePool.terminate(); mStagePool.terminate();
mPipelineCache.terminate(); mPipelineCache.terminate();
mFramebufferCache.terminate(); mFramebufferCache.terminate();
@@ -384,10 +381,6 @@ void VulkanDriver::beginFrame(int64_t monotonic_clock_ns,
int64_t refreshIntervalNs, uint32_t frameId) { int64_t refreshIntervalNs, uint32_t frameId) {
FVK_PROFILE_MARKER(PROFILE_NAME_BEGINFRAME); FVK_PROFILE_MARKER(PROFILE_NAME_BEGINFRAME);
// Do nothing. // Do nothing.
if (mAppState.hasExternalSamplers()) {
mExternalImageManager.onBeginFrame();
}
} }
void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler, void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
@@ -428,17 +421,12 @@ void VulkanDriver::updateDescriptorSetTexture(
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh); auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th); auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
if (mExternalImageManager.isExternallySampledTexture(texture)) { // TODO: YcbcrConversion?
mExternalImageManager.bindExternallySampledTexture(set, binding, texture, params); VulkanSamplerCache::Params cacheParams = {
mAppState.hasBoundExternalImages = true; .sampler = params,
} else { };
VulkanSamplerCache::Params cacheParams = { VkSampler const vksampler = mSamplerCache.getSampler(cacheParams);
.sampler = params, mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
};
VkSampler const vksampler = mSamplerCache.getSampler(cacheParams);
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
mExternalImageManager.clearTextureBinding(set, binding);
}
} }
void VulkanDriver::flush(int) { void VulkanDriver::flush(int) {
@@ -458,7 +446,6 @@ void VulkanDriver::finish(int dummy) {
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh, Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt) { PrimitiveType pt) {
FVK_SYSTRACE_SCOPE();
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh); auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh); auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
auto ptr = resource_ptr<VulkanRenderPrimitive>::make(&mResourceManager, rph, pt, vb, ib); auto ptr = resource_ptr<VulkanRenderPrimitive>::make(&mResourceManager, rph, pt, vb, ib);
@@ -469,14 +456,12 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
if (!rph) { if (!rph) {
return; return;
} }
FVK_SYSTRACE_SCOPE();
auto ptr = resource_ptr<VulkanRenderPrimitive>::cast(&mResourceManager, rph); auto ptr = resource_ptr<VulkanRenderPrimitive>::cast(&mResourceManager, rph);
ptr.dec(); ptr.dec();
} }
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount, void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes) { uint8_t attributeCount, AttributeArray attributes) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount, auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
attributeCount, attributes); attributeCount, attributes);
vbi.inc(); vbi.inc();
@@ -486,14 +471,12 @@ void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
if (!vbih) { if (!vbih) {
return; return;
} }
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih); auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
vbi.dec(); vbi.dec();
} }
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount, void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih) { Handle<HwVertexBufferInfo> vbih) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih); auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool, auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
vertexCount, vbi); vertexCount, vbi);
@@ -504,14 +487,12 @@ void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
if (!vbh) { if (!vbh) {
return; return;
} }
FVK_SYSTRACE_SCOPE();
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh); auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
vb.dec(); vb.dec();
} }
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType, void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage) { uint32_t indexCount, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto elementSize = (uint8_t) getElementTypeSize(elementType); auto elementSize = (uint8_t) getElementTypeSize(elementType);
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool, auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool,
elementSize, indexCount); elementSize, indexCount);
@@ -522,14 +503,12 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
if (!ibh) { if (!ibh) {
return; return;
} }
FVK_SYSTRACE_SCOPE();
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh); auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
ib.dec(); ib.dec();
} }
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount, void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage) { BufferObjectBinding bindingType, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool, auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool,
byteCount, bindingType); byteCount, bindingType);
bo.inc(); bo.inc();
@@ -539,7 +518,6 @@ void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
if (!boh) { if (!boh) {
return; return;
} }
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh); auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
bo.dec(); bo.dec();
} }
@@ -585,48 +563,41 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
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) {
FVK_SYSTRACE_SCOPE(); FVK_SYSTRACE_SCOPE();
auto metadata = mPlatform->extractExternalImageMetadata(externalImage); auto const& metadata = mPlatform->getExternalImageMetadata(externalImage);
if (metadata.isProtected) {
usage |= backend::TextureUsage::PROTECTED;
}
VkImageUsageFlags vkUsage = metadata.usage;
if (any(usage & TextureUsage::BLIT_SRC)) {
vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
if (any(usage & (TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE))) {
vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
assert_invariant(width == metadata.width); assert_invariant(width == metadata.width);
assert_invariant(height == metadata.height); assert_invariant(height == metadata.height);
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
// We do not check the format since AHB could return both a known format and an external format. VkMemoryPropertyFlags const requiredMemoryFlags = any(usage & TextureUsage::UPLOADABLE)
// In which case, we choose one or the other, but this choice is not known to the client. ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
// Therefore the following lines are commented out. : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
// assert_invariant(format == metadata.filamentFormat); uint32_t const memoryTypeIndex =
// assert_invariant(fvkutils::getVkFormat(format) == metadata.format); mContext.selectMemoryType(metadata.memoryTypeBits, requiredMemoryFlags);
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex != VK_MAX_MEMORY_TYPES)
<< "failed to find a valid memory type for external image memory.";
auto imgData = mPlatform->createVkImageFromExternal(externalImage); VkImage vkimg;
VkDeviceMemory deviceMemory;
std::tie(vkimg, deviceMemory) =
mPlatform->createExternalImageData(externalImage, metadata, memoryTypeIndex, vkUsage);
assert_invariant(imgData.internal.valid() || imgData.external.valid());
VkFormat vkformat = metadata.format;
VkImage vkimage = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
if (imgData.internal.valid()) {
metadata.externalFormat = 0;
vkimage = imgData.internal.image;
memory = imgData.internal.memory;
} else { // imgData.external.valid()
vkformat = VK_FORMAT_UNDEFINED;
vkimage = imgData.external.image;
memory = imgData.external.memory;
}
VkSamplerYcbcrConversion const conversion =
mExternalImageManager.getVkSamplerYcbcrConversion(metadata);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mContext, auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mContext,
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, vkimage, memory, mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, vkimg, deviceMemory,
vkformat, conversion, metadata.samples, metadata.width, metadata.height, metadata.format, VK_NULL_HANDLE, metadata.samples, metadata.width, metadata.height,
metadata.layers, usage, mStagePool); metadata.layerCount, usage, mStagePool);
auto& commands = mCommands.get();
// Unlike uploaded textures or swapchains, we need to explicit transition this
// texture into the read layout.
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::READ_ONLY);
if (imgData.external.valid()) {
mExternalImageManager.addExternallySampledTexture(texture, externalImage);
}
texture.inc(); texture.inc();
} }
@@ -659,8 +630,6 @@ void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
} }
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th); auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
texture.dec(); texture.dec();
mExternalImageManager.removeExternallySampledTexture(texture);
} }
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program) { void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
@@ -777,7 +746,6 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
} }
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) { void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
FVK_SYSTRACE_SCOPE();
// Running gc() to guard against an edge case where the old swapchains need to have been // Running gc() to guard against an edge case where the old swapchains need to have been
// destroyed before the new swapchain can be created. Otherwise, we would fail // destroyed before the new swapchain can be created. Otherwise, we would fail
// vkCreateSwapchainKHR with VK_ERROR_NATIVE_WINDOW_IN_USE_KHR. // vkCreateSwapchainKHR with VK_ERROR_NATIVE_WINDOW_IN_USE_KHR.
@@ -819,7 +787,6 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh, void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
backend::DescriptorSetLayout&& info) { backend::DescriptorSetLayout&& info) {
FVK_SYSTRACE_SCOPE();
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info)); auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
layout.inc(); layout.inc();
} }
@@ -831,10 +798,6 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh); fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
auto set = mDescriptorSetCache.createSet(dsh, layout); auto set = mDescriptorSetCache.createSet(dsh, layout);
set.inc(); set.inc();
if (layout->hasExternalSamplers()) {
mAppState.hasExternalSamplerLayouts = true;
}
} }
Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept { Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept {
@@ -959,10 +922,6 @@ void VulkanDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> dslh
void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) { void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh); auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
set.dec(); set.dec();
if (mAppState.hasExternalSamplers() && set->getExternalSamplerVkSet() != VK_NULL_HANDLE) {
mExternalImageManager.removeDescriptorSet(set);
}
} }
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream) { Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream) {
@@ -1523,6 +1482,7 @@ void VulkanDriver::endRenderPass(int) {
// pipeline barrier between framebuffer writes and shader reads. // pipeline barrier between framebuffer writes and shader reads.
rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer); rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer);
mRenderPassFboInfo = {};
mCurrentRenderPass.renderTarget = {}; mCurrentRenderPass.renderTarget = {};
mCurrentRenderPass.renderPass = VK_NULL_HANDLE; mCurrentRenderPass.renderPass = VK_NULL_HANDLE;
@@ -1582,10 +1542,10 @@ void VulkanDriver::commit(Handle<HwSwapChain> sch) {
void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) { backend::PushConstantVariant value) {
assert_invariant(mPipelineState.program && "Expect a program when writing to push constants"); assert_invariant(mBoundPipeline.program && "Expect a program when writing to push constants");
assert_invariant(mCurrentRenderPass.commandBuffer && "Should be called within a renderpass"); assert_invariant(mCurrentRenderPass.commandBuffer && "Should be called within a renderpass");
mPipelineState.program->writePushConstant(mCurrentRenderPass.commandBuffer->buffer(), mBoundPipeline.program->writePushConstant(mCurrentRenderPass.commandBuffer->buffer(),
mPipelineState.pipelineLayout, stage, index, value); mBoundPipeline.pipelineLayout, stage, index, value);
} }
void VulkanDriver::insertEventMarker(char const* string) { void VulkanDriver::insertEventMarker(char const* string) {
@@ -1764,69 +1724,16 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
} }
void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
// This resets all of the pipeline states; the most relevant (needing reset) is .bindInDraw.
mPipelineState = {};
auto& setLayouts = pipelineState.pipelineLayout.setLayout;
DescriptorSetLayoutHandleList layoutHandles;
uint8_t layoutCount = 0;
std::transform(setLayouts.begin(), setLayouts.end(), layoutHandles.begin(),
[&](auto const& handle) -> resource_ptr<VulkanDescriptorSetLayout> {
if (!handle) {
return {};
}
layoutCount++;
return resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, handle);
});
constexpr uint8_t descriptorSetMaskTable[4] = {0x1, 0x3, 0x7, 0xF};
fvkutils::DescriptorSetMask const descriptorSetMask =
fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]);
if (mAppState.hasExternalSamplers()) {
auto const haveExternalSamplers = [&](auto layoutHandle) {
if (!layoutHandle) {
return false;
}
return layoutHandle->hasExternalSamplers();
};
if (std::any_of(layoutHandles.begin(), layoutHandles.end(), haveExternalSamplers)) {
BindInDrawBundle bundle = {
.pipelineState = pipelineState,
.dsLayoutHandles = layoutHandles,
.descriptorSetMask = descriptorSetMask,
};
mPipelineState.bindInDraw = { true, bundle };
return;
}
}
// The normal, non-external sampler path
using VkDescriptorSetLayoutArray = VulkanPipelineLayoutCache::DescriptorSetLayoutArray;
VkDescriptorSetLayoutArray vkLayouts;
std::transform(layoutHandles.begin(), layoutHandles.end(), vkLayouts.begin(),
[](auto const& layout) -> VkDescriptorSetLayout {
if (!layout) {
return VK_NULL_HANDLE;
}
return layout->getVkLayout();
});
auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, pipelineState.program);
auto pipelineLayout = mPipelineLayoutCache.getLayout(vkLayouts, program);
bindPipelineImpl(pipelineState, pipelineLayout, descriptorSetMask);
}
void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask descriptorSetMask) {
FVK_SYSTRACE_SCOPE(); FVK_SYSTRACE_SCOPE();
auto commands = mCurrentRenderPass.commandBuffer; auto commands = mCurrentRenderPass.commandBuffer;
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager,
pipelineState.vertexBufferInfo); pipelineState.vertexBufferInfo);
Handle<HwProgram> programHandle = pipelineState.program;
RasterState const& rasterState = pipelineState.rasterState; RasterState const& rasterState = pipelineState.rasterState;
PolygonOffset const& depthOffset = pipelineState.polygonOffset; PolygonOffset const& depthOffset = pipelineState.polygonOffset;
auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, pipelineState.program); auto program = resource_ptr<VulkanProgram>::cast(&mResourceManager, programHandle);
commands->acquire(program); commands->acquire(program);
// Update the VK raster state. // Update the VK raster state.
@@ -1868,11 +1775,28 @@ void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
mPipelineCache.bindPrimitiveTopology(topology); mPipelineCache.bindPrimitiveTopology(topology);
mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount()); mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount());
// Note that we cannot reinit mPipeline because the .bindInDraw metadata that needs to carry auto& setLayouts = pipelineState.pipelineLayout.setLayout;
// over even on bind. VulkanDescriptorSetLayout::DescriptorSetLayoutArray layoutList;
mPipelineState.program = program; uint8_t layoutCount = 0;
mPipelineState.pipelineLayout = pipelineLayout; std::transform(setLayouts.begin(), setLayouts.end(), layoutList.begin(),
mPipelineState.descriptorSetMask = descriptorSetMask; [&](Handle<HwDescriptorSetLayout> handle) -> VkDescriptorSetLayout {
if (!handle) {
return VK_NULL_HANDLE;
}
auto layout =
resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, handle);
layoutCount++;
return layout->getVkLayout();
});
auto pipelineLayout = mPipelineLayoutCache.getLayout(layoutList, program);
constexpr uint8_t descriptorSetMaskTable[4] = {0x1, 0x3, 0x7, 0xF};
mBoundPipeline = {
.program = program,
.pipelineLayout = pipelineLayout,
.descriptorSetMask = fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]),
};
mPipelineCache.bindLayout(pipelineLayout); mPipelineCache.bindLayout(pipelineLayout);
mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer); mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer);
@@ -1917,41 +1841,15 @@ void VulkanDriver::bindDescriptorSet(
void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) { void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
FVK_SYSTRACE_SCOPE(); FVK_SYSTRACE_SCOPE();
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
auto const& [doBindInDraw, bundle] = mPipelineState.bindInDraw;
fvkutils::DescriptorSetMask setsWithExternalSamplers = {}; mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
if (doBindInDraw) { mBoundPipeline.pipelineLayout,
auto& layoutHandles = bundle.dsLayoutHandles; mBoundPipeline.descriptorSetMask);
setsWithExternalSamplers = mExternalImageManager.prepareBindSets(layoutHandles,
mDescriptorSetCache.getBoundSets());
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vklayouts;
for (size_t i = 0; i < layoutHandles.size(); i++) {
if (!layoutHandles[i]) {
vklayouts[i] = VK_NULL_HANDLE;
continue;
}
if (setsWithExternalSamplers[i]) {
vklayouts[i] = layoutHandles[i]->getExternalSamplerVkLayout();
} else {
vklayouts[i] = layoutHandles[i]->getVkLayout();
}
}
auto program =
resource_ptr<VulkanProgram>::cast(&mResourceManager, bundle.pipelineState.program);
VkPipelineLayout const pipelineLayout = mPipelineLayoutCache.getLayout(vklayouts, program);
if (pipelineLayout != mPipelineState.pipelineLayout) {
bindPipelineImpl(bundle.pipelineState, pipelineLayout, bundle.descriptorSetMask);
}
mPipelineState.bindInDraw.first = false;
}
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer, mPipelineState.pipelineLayout,
setsWithExternalSamplers, mPipelineState.descriptorSetMask);
// Finally, make the actual draw call. TODO: support subranges // Finally, make the actual draw call. TODO: support subranges
uint32_t const firstIndex = indexOffset; const uint32_t firstIndex = indexOffset;
constexpr int32_t vertexOffset = 0; const int32_t vertexOffset = 0;
constexpr uint32_t firstInstId = 0; const uint32_t firstInstId = 0;
vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId); vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId);
} }
+13 -34
View File
@@ -30,7 +30,6 @@
#include "VulkanYcbcrConversionCache.h" #include "VulkanYcbcrConversionCache.h"
#include "vulkan/VulkanDescriptorSetCache.h" #include "vulkan/VulkanDescriptorSetCache.h"
#include "vulkan/VulkanDescriptorSetLayoutCache.h" #include "vulkan/VulkanDescriptorSetLayoutCache.h"
#include "vulkan/VulkanExternalImageManager.h"
#include "vulkan/VulkanPipelineLayoutCache.h" #include "vulkan/VulkanPipelineLayoutCache.h"
#include "vulkan/memory/ResourceManager.h" #include "vulkan/memory/ResourceManager.h"
#include "vulkan/memory/ResourcePointer.h" #include "vulkan/memory/ResourcePointer.h"
@@ -55,7 +54,7 @@ constexpr uint8_t MAX_RENDERTARGET_ATTACHMENT_TEXTURES =
class VulkanDriver final : public DriverBase { class VulkanDriver final : public DriverBase {
public: public:
static Driver* create(VulkanPlatform* platform, VulkanContext const& context, static Driver* create(VulkanPlatform* platform, VulkanContext const& context,
Platform::DriverConfig const& driverConfig); Platform::DriverConfig const& driverConfig) noexcept;
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS) #if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
// Encapsulates the VK_EXT_debug_utils extension. In particular, we use // Encapsulates the VK_EXT_debug_utils extension. In particular, we use
@@ -90,8 +89,8 @@ private:
void debugCommandBegin(CommandStream* cmds, bool synchronous, void debugCommandBegin(CommandStream* cmds, bool synchronous,
const char* methodName) noexcept override; const char* methodName) noexcept override;
VulkanDriver(VulkanPlatform* platform, VulkanContext const& context, inline VulkanDriver(VulkanPlatform* platform, VulkanContext const& context,
Platform::DriverConfig const& driverConfig); Platform::DriverConfig const& driverConfig) noexcept;
~VulkanDriver() noexcept override; ~VulkanDriver() noexcept override;
@@ -120,8 +119,6 @@ private:
private: private:
void collectGarbage(); void collectGarbage();
void bindPipelineImpl(PipelineState const& pipelineState, VkPipelineLayout pipelineLayout,
fvkutils::DescriptorSetMask descriptorSetMask);
VulkanPlatform* mPlatform = nullptr; VulkanPlatform* mPlatform = nullptr;
fvkmemory::ResourceManager mResourceManager; fvkmemory::ResourceManager mResourceManager;
@@ -146,39 +143,21 @@ private:
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache; VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
VulkanDescriptorSetCache mDescriptorSetCache; VulkanDescriptorSetCache mDescriptorSetCache;
VulkanQueryManager mQueryManager; VulkanQueryManager mQueryManager;
VulkanExternalImageManager mExternalImageManager;
// This is necessary for us to write to push constants after binding a pipeline. // This is necessary for us to write to push constants after binding a pipeline.
using DescriptorSetLayoutHandleList = std::array<resource_ptr<VulkanDescriptorSetLayout>,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
struct BindInDrawBundle {
PipelineState pipelineState = {};
DescriptorSetLayoutHandleList dsLayoutHandles = {};
fvkutils::DescriptorSetMask descriptorSetMask = {};
resource_ptr<VulkanProgram> program = {};
};
struct { struct {
// For push constant resource_ptr<VulkanProgram> program;
resource_ptr<VulkanProgram> program = {}; VkPipelineLayout pipelineLayout;
// For push commiting dynamic ubos in draw() fvkutils::DescriptorSetMask descriptorSetMask;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; } mBoundPipeline = {};
fvkutils::DescriptorSetMask descriptorSetMask = {};
std::pair<bool, BindInDrawBundle> bindInDraw = {false, {}};
} mPipelineState = {};
// We need to store information about a render pass to enable better barriers at the end of a
// renderpass.
struct { struct {
// This tracks whether the app has seen external samplers bound to a the descriptor set. using AttachmentArray =
// This will force bindPipeline to take a slow path. fvkutils::StaticVector<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
bool hasExternalSamplerLayouts = false; AttachmentArray attachments;
bool hasBoundExternalImages = false; } mRenderPassFboInfo = {};
bool hasExternalSamplers() const noexcept {
return hasExternalSamplerLayouts && hasBoundExternalImages;
}
} mAppState;
bool const mIsSRGBSwapChainSupported; bool const mIsSRGBSwapChainSupported;
backend::StereoscopicType const mStereoscopicType; backend::StereoscopicType const mStereoscopicType;
@@ -1,294 +0,0 @@
/*
* 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 "VulkanExternalImageManager.h"
#include "VulkanDescriptorSetCache.h"
#include "VulkanDescriptorSetLayoutCache.h"
#include "VulkanSamplerCache.h"
#include "VulkanYcbcrConversionCache.h"
#include "vulkan/memory/ResourcePointer.h"
#include "vulkan/utils/Conversion.h"
#include <backend/platforms/VulkanPlatform.h>
#include <algorithm>
namespace filament::backend {
namespace {
using Bitmask = fvkutils::UniformBufferBitmask;
static_assert(sizeof(Bitmask) * 8 == fvkutils::MAX_DESCRIPTOR_SET_BITMASK_BITS);
template<typename T>
void erasep(std::vector<T>& v, std::function<bool(T const&)> f) {
auto newEnd = std::remove_if(v.begin(), v.end(), f);
v.erase(newEnd, v.end());
}
using ImageData = VulkanExternalImageManager::VulkanExternalImageManager::ImageData;
ImageData& findImage(std::vector<ImageData>& images,
fvkmemory::resource_ptr<VulkanTexture> texture) {
auto itr = std::find_if(images.begin(), images.end(), [&](ImageData const& data) {
return data.image == texture;
});
assert_invariant(itr != images.end());
return *itr;
}
void copySet(VkDevice device, VkDescriptorSet srcSet, VkDescriptorSet dstSet, Bitmask bindings) {
// TODO: fix the size for better memory management
std::vector<VkCopyDescriptorSet> copies;
bindings.forEachSetBit([&](size_t index) {
copies.push_back({
.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
.srcSet = srcSet,
.srcBinding = (uint32_t) index,
.dstSet = dstSet,
.dstBinding = (uint32_t) index,
.descriptorCount = 1,
});
});
vkUpdateDescriptorSets(device, 0, nullptr, copies.size(), copies.data());
}
Bitmask foldBitsInHalf(Bitmask bitset) {
Bitmask outBitset;
bitset.forEachSetBit([&](size_t index) {
constexpr size_t BITMASK_LOWER_BITS_LEN = sizeof(outBitset) * 4;
outBitset.set(index % BITMASK_LOWER_BITS_LEN);
});
return outBitset;
}
}// namespace
VulkanExternalImageManager::VulkanExternalImageManager(VulkanPlatform* platform,
VulkanSamplerCache* samplerCache, VulkanYcbcrConversionCache* ycbcrConversionCache,
VulkanDescriptorSetCache* setCache, VulkanDescriptorSetLayoutCache* layoutCache)
: mPlatform(platform),
mSamplerCache(samplerCache),
mYcbcrConversionCache(ycbcrConversionCache),
mDescriptorSetCache(setCache),
mDescriptorSetLayoutCache(layoutCache) {
}
VulkanExternalImageManager::~VulkanExternalImageManager() = default;
void VulkanExternalImageManager::terminate() {
mSetBindings.clear();
mImages.clear();
}
void VulkanExternalImageManager::onBeginFrame() {
std::for_each(mImages.begin(), mImages.end(), [](ImageData& image) {
image.hasBeenValidated = false;
});
std::for_each(mSetBindings.begin(), mSetBindings.end(), [](SetBindingInfo& info) {
info.bound = false;
});
}
fvkutils::DescriptorSetMask VulkanExternalImageManager::prepareBindSets(LayoutArray const& layouts,
SetArray const& sets) {
fvkutils::DescriptorSetMask shouldUseExternalSampler{};
for (uint8_t i = 0; i < sets.size(); i++) {
auto set = sets[i];
auto layout = layouts[i];
if (!set || !layout) {
continue;
}
if (hasExternalSampler(set)) {
updateSetAndLayout(set, layout);
shouldUseExternalSampler.set(i);
}
}
return shouldUseExternalSampler;
}
bool VulkanExternalImageManager::hasExternalSampler(
fvkmemory::resource_ptr<VulkanDescriptorSet> set) {
auto itr = std::find_if(mSetBindings.begin(), mSetBindings.end(),
[&](SetBindingInfo const& info) { return info.set == set; });
return itr != mSetBindings.end();
}
void VulkanExternalImageManager::updateSetAndLayout(
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
utils::FixedCapacityVector<
std::tuple<uint8_t, VkSampler, fvkmemory::resource_ptr<VulkanTexture>>>
samplerAndBindings;
samplerAndBindings.reserve(MAX_SAMPLER_COUNT);
fvkutils::SamplerBitmask actualExternalSamplers;
for (auto& bindingInfo : mSetBindings) {
if (bindingInfo.set != set || bindingInfo.bound) {
continue;
}
auto& imageData = findImage(mImages, bindingInfo.image);
updateImage(&imageData);
auto samplerParams = bindingInfo.samplerParams;
// according to spec, these must match chromaFilter
// https://registry.khronos.org/vulkan/specs/latest/man/html/VkSamplerCreateInfo.html#VUID-VkSamplerCreateInfo-minFilter-01645
samplerParams.filterMag = SamplerMagFilter::NEAREST;
samplerParams.filterMin = SamplerMinFilter::NEAREST;
auto sampler = mSamplerCache->getSampler({
.sampler = samplerParams,
.conversion = imageData.conversion,
});
actualExternalSamplers.set(bindingInfo.binding);
samplerAndBindings.push_back({ bindingInfo.binding, sampler, bindingInfo.image });
bindingInfo.bound = true;
}
if (samplerAndBindings.empty()) {
return;
}
// Sort by binding number
std::sort(samplerAndBindings.begin(), samplerAndBindings.end(), [](auto const& a, auto const& b) {
return std::get<0>(a) < std::get<0>(b);
});
utils::FixedCapacityVector<VkSampler> outSamplers;
outSamplers.reserve(MAX_SAMPLER_COUNT);
std::for_each(samplerAndBindings.begin(), samplerAndBindings.end(),
[&](auto const& b) { outSamplers.push_back(std::get<1>(b)); });
VkDescriptorSetLayout const oldLayout = layout->getExternalSamplerVkLayout();
VkDescriptorSetLayout const newLayout = mDescriptorSetLayoutCache->getVkLayout(layout->bitmask,
actualExternalSamplers, outSamplers);
// Need to copy the set
VkDescriptorSet const oldSet = set->getExternalSamplerVkSet();
if (oldLayout != newLayout || oldSet == VK_NULL_HANDLE) {
// Build a new descriptor set from the new layout
VkDescriptorSet const newSet = mDescriptorSetCache->getVkSet(layout->count, newLayout);
auto const ubo = layout->bitmask.ubo | layout->bitmask.dynamicUbo;
auto const samplers = layout->bitmask.sampler & (~actualExternalSamplers);
// Each bitmask denotes a binding index, and separated into two stages - vertex and buffer
// We fold the two stages into just the lower half of the bits to denote a combined set of
// bindings.
Bitmask const copyBindings = foldBitsInHalf(ubo | samplers);
VkDescriptorSet const srcSet = oldSet != VK_NULL_HANDLE ? oldSet : set->getVkSet();
copySet(mPlatform->getDevice(), srcSet, newSet, copyBindings);
set->setExternalSamplerVkSet(newSet, [&](VulkanDescriptorSet*) {
mDescriptorSetCache->manualRecycle(layout->count, newLayout, newSet);
});
if (oldLayout != newLayout) {
layout->setExternalSamplerVkLayout(newLayout);
}
}
// Update the external samplers in the set
for (auto& [binding, sampler, image]: samplerAndBindings) {
mDescriptorSetCache->updateSamplerForExternalSamplerSet(set, binding, image);
}
}
VkSamplerYcbcrConversion VulkanExternalImageManager::getVkSamplerYcbcrConversion(
VulkanPlatform::ExternalImageMetadata const& metadata) {
// This external image does not require external sampler (YUV conversion).
if (metadata.externalFormat == 0 && !fvkutils::isVKYcbcrConversionFormat(metadata.format)) {
return VK_NULL_HANDLE;
}
VulkanYcbcrConversionCache::Params ycbcrParams = {
.conversion = {
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(metadata.ycbcrModel),
.r = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.r, 0),
.g = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.g, 1),
.b = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.b, 2),
.a = fvkutils::getSwizzleFilament(metadata.ycbcrConversionComponents.a, 3),
.ycbcrRange = fvkutils::getYcbcrRangeFilament(metadata.ycbcrRange),
.xChromaOffset = fvkutils::getChromaLocationFilament(metadata.xChromaOffset),
.yChromaOffset = fvkutils::getChromaLocationFilament(metadata.yChromaOffset),
// Unclear where to get the chromaFilter, we just assume it's nearest.
.chromaFilter = SamplerMagFilter::NEAREST,
},
.format = metadata.format,
.externalFormat = metadata.externalFormat,
};
return mYcbcrConversionCache->getConversion(ycbcrParams);
}
void VulkanExternalImageManager::updateImage(ImageData* image) {
if (image->hasBeenValidated) {
return;
}
image->hasBeenValidated = true;
auto metadata = mPlatform->extractExternalImageMetadata(image->platformHandle);
auto vkYcbcr = getVkSamplerYcbcrConversion(metadata);
if (vkYcbcr == image->conversion) {
return;
}
image->image->setYcbcrConversion(vkYcbcr);
image->conversion = vkYcbcr;
return;
}
void VulkanExternalImageManager::removeDescriptorSet(
fvkmemory::resource_ptr<VulkanDescriptorSet> inSet) {
erasep<SetBindingInfo>(mSetBindings,
[&](auto const& bindingInfo) { return (bindingInfo.set == inSet); });
}
void VulkanExternalImageManager::bindExternallySampledTexture(
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t bindingPoint,
fvkmemory::resource_ptr<VulkanTexture> image, SamplerParams samplerParams) {
// Should we do duplicate validation here?
auto& imageData = findImage(mImages, image);
mSetBindings.push_back({ bindingPoint, imageData.image, set, samplerParams });
}
void VulkanExternalImageManager::addExternallySampledTexture(
fvkmemory::resource_ptr<VulkanTexture> image,
Platform::ExternalImageHandleRef platformHandleRef) {
mImages.push_back({ image, platformHandleRef, false });
}
void VulkanExternalImageManager::removeExternallySampledTexture(
fvkmemory::resource_ptr<VulkanTexture> image) {
erasep<SetBindingInfo>(mSetBindings,
[&](auto const& bindingInfo) { return (bindingInfo.image == image); });
erasep<ImageData>(mImages, [&](auto const& imageData) {
return imageData.image == image;
});
}
bool VulkanExternalImageManager::isExternallySampledTexture(
fvkmemory::resource_ptr<VulkanTexture> image) const {
return std::find_if(mImages.begin(), mImages.end(), [&](auto const& imageData) {
return imageData.image == image;
}) != mImages.end();
}
void VulkanExternalImageManager::clearTextureBinding(
fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t bindingPoint) {
erasep<SetBindingInfo>(mSetBindings, [&](auto const& bindingInfo) {
return (bindingInfo.set == set && bindingInfo.binding == bindingPoint);
});
}
} // namesapce filament::backend
@@ -1,121 +0,0 @@
/*
* 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_CACHING_VULKANEXTERNALIMAGEMANAGER_H
#define TNT_FILAMENT_BACKEND_CACHING_VULKANEXTERNALIMAGEMANAGER_H
#include "VulkanHandles.h"
#include <backend/DriverEnums.h>
#include <array>
#include <vector>
namespace filament::backend {
class VulkanYcbcrConversionCache;
class VulkanSamplerCache;
class VulkanDescriptorSetLayoutCache;
class VulkanDescriptorSetCache;
// Manages the logic of external images and their quirks wrt Vulikan.
class VulkanExternalImageManager {
public:
VulkanExternalImageManager(
VulkanPlatform* platform,
VulkanSamplerCache* samplerCache,
VulkanYcbcrConversionCache* ycbcrConversionCache,
VulkanDescriptorSetCache* setCache,
VulkanDescriptorSetLayoutCache* layoutCache);
~VulkanExternalImageManager();
void terminate();
void onBeginFrame();
using SetArray = std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
using LayoutArray = std::array<fvkmemory::resource_ptr<VulkanDescriptorSetLayout>,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
using VkLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
// Returns bitmask to indicate whether or not to use the external sampler version of each
// descriptor set.
fvkutils::DescriptorSetMask prepareBindSets(LayoutArray const& layouts, SetArray const& sets);
void removeDescriptorSet(fvkmemory::resource_ptr<VulkanDescriptorSet> set);
void bindExternallySampledTexture(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
uint8_t bindingPoint, fvkmemory::resource_ptr<VulkanTexture> image,
SamplerParams samplerParams);
void clearTextureBinding(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
uint8_t bindingPoint);
void addExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> external,
Platform::ExternalImageHandleRef platformHandleRef);
void removeExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> image);
bool isExternallySampledTexture(fvkmemory::resource_ptr<VulkanTexture> image) const;
VkSamplerYcbcrConversion getVkSamplerYcbcrConversion(
VulkanPlatform::ExternalImageMetadata const& metadata);
struct ImageData {
fvkmemory::resource_ptr<VulkanTexture> image;
Platform::ExternalImageHandle platformHandle;
bool hasBeenValidated = false; // indicates whether the image has been validated *this frame*
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
};
private:
bool hasExternalSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set);
void updateSetAndLayout(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
void updateImage(ImageData* imageData);
VulkanPlatform* mPlatform;
VulkanSamplerCache* mSamplerCache;
VulkanYcbcrConversionCache* mYcbcrConversionCache;
VulkanDescriptorSetCache* mDescriptorSetCache;
VulkanDescriptorSetLayoutCache* mDescriptorSetLayoutCache;
using SetAndLayout = std::pair<fvkmemory::resource_ptr<VulkanDescriptorSet>,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>>;
struct SetBindingInfo {
uint8_t binding = 0;
fvkmemory::resource_ptr<VulkanTexture> image;
fvkmemory::resource_ptr<VulkanDescriptorSet> set;
SamplerParams samplerParams;
bool bound = false;
};
// Use vectors instead of hash maps because we only expect small number of entries.
std::vector<SetBindingInfo> mSetBindings;
std::vector<ImageData> mImages;
};
} // filament::backend
#endif // TNT_FILAMENT_BACKEND_CACHING_VULKANEXTERNALIMAGEMANAGER_H
+6 -14
View File
@@ -330,20 +330,12 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept
mRenderPassCache[config] = {renderPass, mCurrentTime}; mRenderPassCache[config] = {renderPass, mCurrentTime};
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE) #if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
FVK_LOGD << "Created render pass " << renderPass << " with "; FVK_LOGD << "Created render pass " << renderPass << " with "
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; ++i) { << "samples = " << int(config.samples) << ", "
FVK_LOGD << (int) config.colorFormat[i] << " "; << "depth = " << (hasDepth ? 1 : 0) << ", "
} << "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
FVK_LOGD << ", " << utils::io::endl;
<< "depth = " << config.depthFormat << ", " #endif
<< "initialDepthLayout = " << (int) config.initialDepthLayout << ", "
<< "samples = " << int(config.samples) << ", "
<< "needsResolveMask = " << int(config.needsResolveMask) << ", "
<< "usesLazilyAllocatedMemory = " << int(config.usesLazilyAllocatedMemory) << ", "
<< "viewCount = " << int(config.viewCount) << ", "
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
<< utils::io::endl;
#endif
return renderPass; return renderPass;
} }
+3 -10
View File
@@ -149,18 +149,11 @@ void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr<VulkanBufferObject> ob
mResources.push_back(obj); mResources.push_back(obj);
} }
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout&& layout, VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& layout)
VkDescriptorSetLayout vkLayout)
: bitmask(fromBackendLayout(layout)), : bitmask(fromBackendLayout(layout)),
count(Count::fromLayoutBitmask(bitmask)), count(Count::fromLayoutBitmask(bitmask)) {}
mVkLayout(vkLayout) {}
VulkanDescriptorSetLayout::Bitmask VulkanDescriptorSetLayout::Bitmask::fromLayoutDescription( PushConstantDescription::PushConstantDescription(backend::Program const& program) noexcept {
DescriptorSetLayout const& layout) {
return fromBackendLayout(layout);
}
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
mRangeCount = 0; mRangeCount = 0;
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) { for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
auto const& constants = program.getPushConstants(stage); auto const& constants = program.getPushConstants(stage);
+13 -40
View File
@@ -71,7 +71,7 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
fvkutils::SamplerBitmask sampler; // 8 bytes fvkutils::SamplerBitmask sampler; // 8 bytes
fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes
// This is a subset of the sampler field. // This is a subset of the bitmask.sampler field.
fvkutils::SamplerBitmask externalSampler; // 8 bytes fvkutils::SamplerBitmask externalSampler; // 8 bytes
bool operator==(Bitmask const& right) const { bool operator==(Bitmask const& right) const {
@@ -79,8 +79,6 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
inputAttachment == right.inputAttachment && inputAttachment == right.inputAttachment &&
externalSampler == right.externalSampler; externalSampler == right.externalSampler;
} }
static Bitmask fromLayoutDescription(DescriptorSetLayout const& layout);
}; };
static_assert(sizeof(Bitmask) == 40); static_assert(sizeof(Bitmask) == 40);
@@ -122,20 +120,16 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
} }
}; };
VulkanDescriptorSetLayout(DescriptorSetLayout&& layout, VkDescriptorSetLayout vkLayout); VulkanDescriptorSetLayout(DescriptorSetLayout const& layout);
// Note that we don't destroy the vklayout. This is done by the layout cache. // Note that we don't destroy the vklayout. This is done by the layout cache.
~VulkanDescriptorSetLayout() = default; ~VulkanDescriptorSetLayout() = default;
VkDescriptorSetLayout getVkLayout() const noexcept { return mVkLayout; } VkDescriptorSetLayout const& getVkLayout() const noexcept { return mVkLayout; }
VkDescriptorSetLayout getExternalSamplerVkLayout() const noexcept { // It is possible to have the layout switch out due to AHardwarebuffer (external image) format
return mExternalSamplerVkLayout; // changes.
} void setVkLayout(VkDescriptorSetLayout vklayout) noexcept { mVkLayout = vklayout; }
void setExternalSamplerVkLayout(VkDescriptorSetLayout vklayout) noexcept {
mExternalSamplerVkLayout = vklayout;
}
bool hasExternalSamplers() const noexcept { return bitmask.externalSampler.count() > 0; } bool hasExternalSamplers() const noexcept { return bitmask.externalSampler.count() > 0; }
@@ -143,11 +137,7 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
Count const count; Count const count;
private: private:
// This is the layout without any immutable samplers. VkDescriptorSetLayout mVkLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout const mVkLayout = VK_NULL_HANDLE;
// This is the layout with immutable samplers, and can be updated.
VkDescriptorSetLayout mExternalSamplerVkLayout = VK_NULL_HANDLE;
}; };
struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource { struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource {
@@ -159,37 +149,23 @@ public:
VulkanDescriptorSet( VulkanDescriptorSet(
fvkutils::UniformBufferBitmask const& dynamicUboMask, fvkutils::UniformBufferBitmask const& dynamicUboMask,
uint8_t uniqueDynamicUboCount, uint8_t uniqueDynamicUboCount,
OnRecycle&& onRecycleFn, VkDescriptorSet vkSet) OnRecycle&& onRecycleFn)
: dynamicUboMask(dynamicUboMask), : dynamicUboMask(dynamicUboMask),
uniqueDynamicUboCount(uniqueDynamicUboCount), uniqueDynamicUboCount(uniqueDynamicUboCount),
mVkSet(vkSet),
mOnRecycleFn(std::move(onRecycleFn)) {} mOnRecycleFn(std::move(onRecycleFn)) {}
// NOLINTNEXTLINE(bugprone-exception-escape)
~VulkanDescriptorSet() { ~VulkanDescriptorSet() {
if (mOnRecycleFn) { if (mOnRecycleFn) {
mOnRecycleFn(this); mOnRecycleFn(this);
} }
if (mOnRecycleExternalSamplerFn) {
mOnRecycleExternalSamplerFn(this);
}
} }
VkDescriptorSet getVkSet() const noexcept { VkDescriptorSet const& getVkSet() const noexcept {
return mVkSet; return mVkSet;
} }
VkDescriptorSet getExternalSamplerVkSet() const noexcept { // Note that the only case where you'd set it more than once is with external images/samplers.
return mExternalSamplerVkSet; void setVkSet(VkDescriptorSet vkset) noexcept { mVkSet = vkset; }
}
void setExternalSamplerVkSet(VkDescriptorSet vkset, OnRecycle onRecycle) {
mExternalSamplerVkSet = vkset;
if (mOnRecycleExternalSamplerFn) {
mOnRecycleExternalSamplerFn(this);
}
mOnRecycleExternalSamplerFn = onRecycle;
}
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept { void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
mOffsets = std::move(offsets); mOffsets = std::move(offsets);
@@ -206,20 +182,17 @@ public:
uint8_t const uniqueDynamicUboCount; uint8_t const uniqueDynamicUboCount;
private: private:
VkDescriptorSet const mVkSet; VkDescriptorSet mVkSet = VK_NULL_HANDLE;
VkDescriptorSet mExternalSamplerVkSet = VK_NULL_HANDLE;
backend::DescriptorSetOffsetArray mOffsets; backend::DescriptorSetOffsetArray mOffsets;
std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources; std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources;
OnRecycle mOnRecycleFn; OnRecycle mOnRecycleFn;
OnRecycle mOnRecycleExternalSamplerFn;
}; };
using PushConstantNameArray = utils::FixedCapacityVector<char const*>; using PushConstantNameArray = utils::FixedCapacityVector<char const*>;
using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>; using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>;
struct PushConstantDescription { struct PushConstantDescription {
explicit PushConstantDescription(backend::Program const& program); explicit PushConstantDescription(backend::Program const& program) noexcept;
VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; } VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; }
uint32_t getVkRangeCount() const noexcept { return mRangeCount; } uint32_t getVkRangeCount() const noexcept { return mRangeCount; }
@@ -66,12 +66,8 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
// If an error occurred, allow higher levels to handle it gracefully. // If an error occurred, allow higher levels to handle it gracefully.
assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline"); assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline");
mBoundPipeline = mPipelineRequirements;
static PipelineEqual equal; vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
if (!equal(mBoundPipeline, mPipelineRequirements)) {
mBoundPipeline = mPipelineRequirements;
vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
}
} }
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept { VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
@@ -335,7 +335,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
mTaskHandler->post(std::move(waitFenceFunc), std::move(cleanPbdFunc)); mTaskHandler->post(std::move(waitFenceFunc), std::move(cleanPbdFunc));
} }
void VulkanReadPixels::runUntilComplete() { void VulkanReadPixels::runUntilComplete() noexcept {
if (!mTaskHandler) { if (!mTaskHandler) {
return; return;
} }
@@ -79,7 +79,7 @@ public:
OnReadCompleteFunction const& readCompleteFunc); OnReadCompleteFunction const& readCompleteFunc);
// This method will block until all of the in-flight requests are complete. // This method will block until all of the in-flight requests are complete.
void runUntilComplete(); void runUntilComplete() noexcept;
private: private:
VkDevice mDevice = VK_NULL_HANDLE; VkDevice mDevice = VK_NULL_HANDLE;
@@ -28,7 +28,7 @@ namespace filament::backend {
VulkanSamplerCache::VulkanSamplerCache(VkDevice device) VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
: mDevice(device) {} : mDevice(device) {}
VkSampler VulkanSamplerCache::getSampler(Params params) { VkSampler VulkanSamplerCache::getSampler(Params params) noexcept {
auto iter = mCache.find(params); auto iter = mCache.find(params);
if (UTILS_LIKELY(iter != mCache.end())) { if (UTILS_LIKELY(iter != mCache.end())) {
return iter->second; return iter->second;
@@ -38,7 +38,7 @@ public:
static_assert(sizeof(Params) == 16); static_assert(sizeof(Params) == 16);
explicit VulkanSamplerCache(VkDevice device); explicit VulkanSamplerCache(VkDevice device);
VkSampler getSampler(Params params); VkSampler getSampler(Params params) noexcept;
void terminate() noexcept; void terminate() noexcept;
private: private:
VkDevice mDevice; VkDevice mDevice;
@@ -24,7 +24,7 @@
#include <utils/Panic.h> #include <utils/Panic.h>
static constexpr uint32_t TIME_BEFORE_EVICTION = 3; static constexpr uint32_t TIME_BEFORE_EVICTION = FVK_MAX_COMMAND_BUFFERS;
namespace filament::backend { namespace filament::backend {
@@ -39,7 +39,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
auto stage = iter->second; auto stage = iter->second;
mFreeStages.erase(iter); mFreeStages.erase(iter);
stage->lastAccessed = mCurrentFrame; stage->lastAccessed = mCurrentFrame;
mUsedStages.push_back(stage); mUsedStages.insert(stage);
return stage; return stage;
} }
// We were not able to find a sufficiently large stage, so create a new one. // We were not able to find a sufficiently large stage, so create a new one.
@@ -51,7 +51,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
}); });
// Create the VkBuffer. // Create the VkBuffer.
mUsedStages.push_back(stage); mUsedStages.insert(stage);
VkBufferCreateInfo bufferInfo { VkBufferCreateInfo bufferInfo {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = numBytes, .size = numBytes,
@@ -77,7 +77,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
if (image->format == vkformat && image->width == width && image->height == height) { if (image->format == vkformat && image->width == width && image->height == height) {
mFreeImages.erase(image); mFreeImages.erase(image);
image->lastAccessed = mCurrentFrame; image->lastAccessed = mCurrentFrame;
mUsedImages.push_back(image); mUsedImages.insert(image);
return image; return image;
} }
} }
@@ -89,7 +89,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
.lastAccessed = mCurrentFrame, .lastAccessed = mCurrentFrame,
}); });
mUsedImages.push_back(image); mUsedImages.insert(image);
const VkImageCreateInfo imageInfo = { const VkImageCreateInfo imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@@ -161,7 +161,7 @@ void VulkanStagePool::gc() noexcept {
stage->lastAccessed = mCurrentFrame; stage->lastAccessed = mCurrentFrame;
mFreeStages.insert(std::make_pair(stage->capacity, stage)); mFreeStages.insert(std::make_pair(stage->capacity, stage));
} else { } else {
mUsedStages.push_back(stage); mUsedStages.insert(stage);
} }
} }
@@ -185,7 +185,7 @@ void VulkanStagePool::gc() noexcept {
image->lastAccessed = mCurrentFrame; image->lastAccessed = mCurrentFrame;
mFreeImages.insert(image); mFreeImages.insert(image);
} else { } else {
mUsedImages.push_back(image); mUsedImages.insert(image);
} }
} }
FVK_SYSTRACE_END(); FVK_SYSTRACE_END();
@@ -22,7 +22,6 @@
#include <map> #include <map>
#include <unordered_set> #include <unordered_set>
#include <vector>
namespace filament::backend { namespace filament::backend {
@@ -74,10 +73,10 @@ private:
std::multimap<uint32_t, VulkanStage const*> mFreeStages; std::multimap<uint32_t, VulkanStage const*> mFreeStages;
// Simple unordered set for stashing a list of in-use stages that can be reclaimed later. // Simple unordered set for stashing a list of in-use stages that can be reclaimed later.
std::vector<VulkanStage const*> mUsedStages; std::unordered_set<VulkanStage const*> mUsedStages;
std::unordered_set<VulkanStageImage const*> mFreeImages; std::unordered_set<VulkanStageImage const*> mFreeImages;
std::vector<VulkanStageImage const*> mUsedImages; std::unordered_set<VulkanStageImage const*> mUsedImages;
// Store the current "time" (really just a frame count) and LRU eviction parameters. // Store the current "time" (really just a frame count) and LRU eviction parameters.
uint64_t mCurrentFrame = 0; uint64_t mCurrentFrame = 0;
+11 -6
View File
@@ -223,7 +223,8 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands,
VmaAllocator allocator, VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VmaAllocator allocator, VkDevice device, VkImage image, VkDeviceMemory deviceMemory,
VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount, VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
VkSamplerYcbcrConversion ycbcrConversion, VkImageUsageFlags usage, bool isProtected) VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat, VkImageUsageFlags usage,
bool isProtected)
: mStagePool(stagePool), : mStagePool(stagePool),
mCommands(commands), mCommands(commands),
mAllocator(allocator), mAllocator(allocator),
@@ -233,17 +234,17 @@ VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommand
mVkFormat(format), mVkFormat(format),
mViewType(viewType), mViewType(viewType),
mFullViewRange{ fvkutils::getImageAspect(format), 0, levels, 0, layerCount }, mFullViewRange{ fvkutils::getImageAspect(format), 0, levels, 0, layerCount },
mYcbcr{ ycbcrConversion }, mYcbcr{ ycbcrConversion, isExternalFormat },
mDefaultLayout(getDefaultLayoutImpl(usage)), mDefaultLayout(getDefaultLayoutImpl(usage)),
mUsage(usage), mUsage(usage),
mIsProtected(isProtected) {} mIsProtected(isProtected) {}
VulkanTextureState::~VulkanTextureState() { VulkanTextureState::~VulkanTextureState() {
clearCachedImageViews();
if (mTextureImageMemory != VK_NULL_HANDLE) { if (mTextureImageMemory != VK_NULL_HANDLE) {
vkDestroyImage(mDevice, mTextureImage, VKALLOC); vkDestroyImage(mDevice, mTextureImage, VKALLOC);
vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC); vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC);
} }
clearCachedImageViews();
} }
void VulkanTextureState::clearCachedImageViews() noexcept { void VulkanTextureState::clearCachedImageViews() noexcept {
@@ -271,7 +272,7 @@ VkImageView VulkanTextureState::getImageView(VkImageSubresourceRange range, VkIm
.flags = 0, .flags = 0,
.image = mTextureImage, .image = mTextureImage,
.viewType = viewType, .viewType = viewType,
.format = mYcbcr.conversion != VK_NULL_HANDLE ? VK_FORMAT_UNDEFINED : mVkFormat, .format = mYcbcr.isExternalFormat ? VK_FORMAT_UNDEFINED : mVkFormat,
.components = swizzle, .components = swizzle,
.subresourceRange = range, .subresourceRange = range,
}; };
@@ -293,6 +294,7 @@ VulkanTexture::VulkanTexture(VulkanContext const& context, VkDevice device, VmaA
commands, allocator, device, image, memory, format, commands, allocator, device, image, memory, format,
fvkutils::getViewType(SamplerType::SAMPLER_2D), fvkutils::getViewType(SamplerType::SAMPLER_2D),
/*mipLevels=*/1, getLayerCountFromDepth(depth), conversion, /*mipLevels=*/1, getLayerCountFromDepth(depth), conversion,
/*isExternalFormat=*/false,
getUsage(context, samples, VK_NULL_HANDLE, format, tusage), getUsage(context, samples, VK_NULL_HANDLE, format, tusage),
any(usage & TextureUsage::PROTECTED))) { any(usage & TextureUsage::PROTECTED))) {
mPrimaryViewRange = mState->mFullViewRange; mPrimaryViewRange = mState->mFullViewRange;
@@ -422,7 +424,8 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
mState = fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool, mState = fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool,
commands, allocator, device, textureImage, textureImageMemory, vkFormat, commands, allocator, device, textureImage, textureImageMemory, vkFormat,
fvkutils::getViewType(target), levels, getLayerCount(target, depth), fvkutils::getViewType(target), levels, getLayerCount(target, depth),
VK_NULL_HANDLE /* ycbcrConversion */, imageInfo.usage, isProtected); VK_NULL_HANDLE /* ycbcrConversion */, false /*isExternalFormat*/, imageInfo.usage,
isProtected);
// Spec out the "primary" VkImageView that shaders use to sample from the image. // Spec out the "primary" VkImageView that shaders use to sample from the image.
mPrimaryViewRange = mState->mFullViewRange; mPrimaryViewRange = mState->mFullViewRange;
@@ -761,13 +764,15 @@ void VulkanTexture::setLayout(VkImageSubresourceRange const& range, VulkanLayout
} }
} }
void VulkanTexture::setYcbcrConversion(VkSamplerYcbcrConversion conversion) { void VulkanTexture::setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternalFormat) {
// Note that this comparison is valid because we only ever create VkSamplerYcbcrConversion from // Note that this comparison is valid because we only ever create VkSamplerYcbcrConversion from
// a cache. So for each set of parameters, there is exactly one conversion (similar to // a cache. So for each set of parameters, there is exactly one conversion (similar to
// samplers). // samplers).
VulkanTextureState::Ycbcr ycbcr = { VulkanTextureState::Ycbcr ycbcr = {
.conversion = conversion, .conversion = conversion,
.isExternalFormat = isExternalFormat,
}; };
if (mState->mYcbcr != ycbcr) { if (mState->mYcbcr != ycbcr) {
mState->mYcbcr = ycbcr; mState->mYcbcr = ycbcr;
mState->clearCachedImageViews(); mState->clearCachedImageViews();
+5 -3
View File
@@ -40,7 +40,8 @@ struct VulkanTextureState : public fvkmemory::Resource {
VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VmaAllocator allocator, VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VmaAllocator allocator,
VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VkFormat format, VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VkFormat format,
VkImageViewType viewType, uint8_t levels, uint8_t layerCount, VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
VkSamplerYcbcrConversion ycbcrConversion, VkImageUsageFlags usage, bool isProtected); VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat,
VkImageUsageFlags usage, bool isProtected);
~VulkanTextureState(); ~VulkanTextureState();
@@ -85,9 +86,10 @@ private:
// conversion matrix per-frame. // conversion matrix per-frame.
struct Ycbcr { struct Ycbcr {
VkSamplerYcbcrConversion conversion; VkSamplerYcbcrConversion conversion;
bool isExternalFormat;
bool operator==(Ycbcr const& other) const { bool operator==(Ycbcr const& other) const {
return conversion == other.conversion; return conversion == other.conversion && isExternalFormat == other.isExternalFormat;
} }
bool operator!=(Ycbcr const& other) const { bool operator!=(Ycbcr const& other) const {
@@ -207,7 +209,7 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
// This is used in the case of external images and external samplers. AHB might update the // This is used in the case of external images and external samplers. AHB might update the
// conversion per-frame. This implies that we need to invalidate the view cache when that // conversion per-frame. This implies that we need to invalidate the view cache when that
// happens. // happens.
void setYcbcrConversion(VkSamplerYcbcrConversion conversion); void setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternal);
#if FVK_ENABLED(FVK_DEBUG_TEXTURE) #if FVK_ENABLED(FVK_DEBUG_TEXTURE)
void print() const; void print() const;
@@ -33,7 +33,7 @@ VulkanYcbcrConversionCache::VulkanYcbcrConversionCache(VkDevice device)
: mDevice(device) {} : mDevice(device) {}
VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion( VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
VulkanYcbcrConversionCache::Params params) { VulkanYcbcrConversionCache::Params params) noexcept {
auto iter = mCache.find(params); auto iter = mCache.find(params);
if (UTILS_LIKELY(iter != mCache.end())) { if (UTILS_LIKELY(iter != mCache.end())) {
return iter->second; return iter->second;
@@ -43,7 +43,7 @@ VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
TextureSwizzle const swizzleArray[] = { chroma.r, chroma.g, chroma.b, chroma.a }; TextureSwizzle const swizzleArray[] = { chroma.r, chroma.g, chroma.b, chroma.a };
VkSamplerYcbcrConversionCreateInfo conversionInfo = { VkSamplerYcbcrConversionCreateInfo conversionInfo = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.format = params.format, .format = fvkutils::getVkFormat(params.format),
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel), .ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange), .ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
.components = fvkutils::getSwizzleMap(swizzleArray), .components = fvkutils::getSwizzleMap(swizzleArray),
@@ -30,14 +30,15 @@ namespace filament::backend {
class VulkanYcbcrConversionCache { class VulkanYcbcrConversionCache {
public: public:
struct Params { struct Params {
SamplerYcbcrConversion conversion = {}; // 4 SamplerYcbcrConversion conversion = {};
VkFormat format; // 4 TextureFormat format = {};
uint64_t externalFormat = 0; // 8 uint16_t padding = 0;
uint64_t externalFormat = 0;
}; };
static_assert(sizeof(Params) == 16); static_assert(sizeof(Params) == 16);
explicit VulkanYcbcrConversionCache(VkDevice device); explicit VulkanYcbcrConversionCache(VkDevice device);
VkSamplerYcbcrConversion getConversion(Params params); VkSamplerYcbcrConversion getConversion(Params params) noexcept;
void terminate() noexcept; void terminate() noexcept;
private: private:
@@ -47,8 +48,7 @@ private:
bool operator()(Params lhs, Params rhs) const noexcept { bool operator()(Params lhs, Params rhs) const noexcept {
SamplerYcbcrConversion::EqualTo equal; SamplerYcbcrConversion::EqualTo equal;
return equal(lhs.conversion, rhs.conversion) && return equal(lhs.conversion, rhs.conversion) &&
lhs.externalFormat == rhs.externalFormat && lhs.externalFormat == rhs.externalFormat;
lhs.format == rhs.format;
} }
}; };
using ConversionHashFn = utils::hash::MurmurHashFn<Params>; using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
@@ -31,8 +31,6 @@ ResourceManager::ResourceManager(size_t arenaSize, bool disableUseAfterFreeCheck
: mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck, disablePoolHandleTags) {} : mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck, disablePoolHandleTags) {}
void ResourceManager::gc() noexcept { void ResourceManager::gc() noexcept {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("ResourceManager::gc");
auto destroyAll = [this](GcList& list) { auto destroyAll = [this](GcList& list) {
for (auto const& [type, id]: list) { for (auto const& [type, id]: list) {
destroyWithType(type, id); destroyWithType(type, id);
@@ -51,7 +49,6 @@ void ResourceManager::gc() noexcept {
GcList gcs; GcList gcs;
std::swap(gcs, mGcList); std::swap(gcs, mGcList);
destroyAll(gcs); destroyAll(gcs);
FVK_SYSTRACE_END();
} }
void ResourceManager::terminate() noexcept { void ResourceManager::terminate() noexcept {
@@ -132,10 +132,6 @@ public:
return id() == other.id() && type() == other.type(); return id() == other.id() && type() == other.type();
} }
inline bool operator!=(resource_ptr<D> const& other) const {
return !((*this) == other);
}
inline explicit operator bool() const { inline explicit operator bool() const {
return bool(mRef); return bool(mRef);
} }
@@ -212,8 +212,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
// This is needed for external images. See VulkanPlatformAndroid
VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
#endif #endif
// MoltenVk is the only non-conformant implementation we're interested in. // MoltenVk is the only non-conformant implementation we're interested in.
#if defined(__APPLE__) #if defined(__APPLE__)
@@ -995,6 +993,30 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
return mImpl->mProtectedGraphicsQueue; return mImpl->mProtectedGraphicsQueue;
} }
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
ExternalImageHandleRef externalImage) {
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata, memoryTypeIndex,
usage);
}
VkSampler VulkanPlatform::createExternalSampler(SamplerYcbcrConversion chroma,
SamplerParams sampler, uint32_t internalFormat) {
return createExternalSamplerImpl(mImpl->mDevice, chroma, sampler, internalFormat);
}
VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chroma,
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
VkImageViewType viewType, VkComponentMapping swizzle) {
return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range,
viewType, swizzle);
}
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const { ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
return getSwapchainInstanceExtensionsImpl(); return getSwapchainInstanceExtensionsImpl();
} }
@@ -15,14 +15,14 @@
*/ */
#include <backend/platforms/VulkanPlatformAndroid.h> #include <backend/platforms/VulkanPlatformAndroid.h>
#include "vulkan/VulkanConstants.h"
#include "vulkan/VulkanContext.h"
#include <backend/DriverEnums.h> #include <backend/DriverEnums.h>
#include <private/backend/BackendUtilsAndroid.h> #include <private/backend/BackendUtilsAndroid.h>
#include "vulkan/VulkanConstants.h"
#include <utils/Panic.h> #include <utils/Panic.h>
#include "vulkan/utils/Image.h" #include "vulkan/utils/Image.h"
#include "vulkan/utils/Conversion.h"
#include <bluevk/BlueVK.h> #include <bluevk/BlueVK.h>
@@ -39,14 +39,6 @@ namespace {
VkFormat transformVkFormat(VkFormat format, bool sRGB) { VkFormat transformVkFormat(VkFormat format, bool sRGB) {
if (!sRGB) { if (!sRGB) {
switch (format) {
case VK_FORMAT_R8G8B8A8_SRGB:
return VK_FORMAT_R8G8B8A8_UNORM;
case VK_FORMAT_R8G8B8_SRGB:
return VK_FORMAT_R8G8B8_UNORM;
default:
break;
}
return format; return format;
} }
@@ -65,7 +57,7 @@ VkFormat transformVkFormat(VkFormat format, bool sRGB) {
} }
bool isProtectedFromUsage(uint64_t usage) { bool isProtectedFromUsage(uint64_t usage) {
return usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT; return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false;
} }
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc,
@@ -128,9 +120,7 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
usage = 0; usage = 0;
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) { if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
usage |= VK_IMAGE_USAGE_SAMPLED_BIT; usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
// We shouldn't be using external samplers as input attachments
// usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
} }
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) { if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
if (isDepthFormat) { if (isDepthFormat) {
@@ -146,37 +136,87 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
return { format, usage }; return { format, usage };
} }
std::pair<TextureFormat, TextureUsage> getFilamentFormatAndUsage(const AHardwareBuffer_Desc& desc, VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
bool sRGB) { VulkanPlatform::ExternalImageMetadata const& metadata, uint32_t memoryTypeIndex,
auto const format = mapToFilamentFormat(desc.format, sRGB); VkImageUsageFlags usage) {
return { VulkanPlatform::ImageData data;
format,
mapToFilamentUsage(desc.usage, format), // if external format we need to specifiy it in the allocation
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
const VkExternalFormatANDROID externalFormat = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
.pNext = nullptr,
// pass down the format (external means we don't have it VK defined)
.externalFormat = metadata.externalFormat,
}; };
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = useExternalFormat ? &externalFormat : nullptr,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
};
VkImageCreateInfo imageInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.pNext = &externalCreateInfo;
imageInfo.format = metadata.format;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent = {
metadata.width,
metadata.height,
1u,
};
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = metadata.layers;
imageInfo.samples = metadata.samples;
imageInfo.usage = usage;
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
// Allocate the memory
VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo = {
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
.pNext = nullptr,
.buffer = buffer,
};
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.pNext = &androidHardwareBufferInfo,
.image = data.first,
.buffer = VK_NULL_HANDLE,
};
VkMemoryAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &memoryDedicatedAllocateInfo,
.allocationSize = metadata.allocationSize,
.memoryTypeIndex = memoryTypeIndex,
};
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
return data;
} }
}// namespace }// namespace
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() { VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
if (__builtin_available(android 26, *)) {
if (aHardwareBuffer) {
AHardwareBuffer_release(aHardwareBuffer);
}
}
}
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage( Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
AHardwareBuffer const* buffer, bool sRGB) noexcept { AHardwareBuffer const* buffer, bool sRGB) noexcept {
if (__builtin_available(android 26, *)) { if (__builtin_available(android 26, *)) {
auto bufferImpl = const_cast<AHardwareBuffer*>(buffer);
AHardwareBuffer_acquire(bufferImpl);
AHardwareBuffer_Desc hardwareBufferDescription = {}; AHardwareBuffer_Desc hardwareBufferDescription = {};
AHardwareBuffer_describe(buffer, &hardwareBufferDescription); AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid; auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer); p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
p->sRGB = sRGB; p->sRGB = sRGB;
p->height = hardwareBufferDescription.height;
p->width = hardwareBufferDescription.width;
TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
p->format = textureFormat;
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
return Platform::ExternalImageHandle{ p }; return Platform::ExternalImageHandle{ p };
} }
@@ -185,20 +225,23 @@ Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc( VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
ExternalImageHandleRef externalImage) const noexcept { ExternalImageHandleRef externalImage) const noexcept {
auto metadata = extractExternalImageMetadata(externalImage); auto const* fvkExternalImage =
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
return { return {
.width = metadata.width, .width = fvkExternalImage->width,
.height = metadata.height, .height = fvkExternalImage->height,
.format = metadata.filamentFormat, .format = fvkExternalImage->format,
.usage = metadata.filamentUsage, .usage = fvkExternalImage->usage,
}; };
} }
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImageMetadata( VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
ExternalImageHandleRef image) const { ExternalImageHandleRef externalImage) {
auto const* fvkExternalImage = static_cast<ExternalImageVulkanAndroid const*>(image.get()); auto const* fvkExternalImage =
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
ExternalImageMetadata metadata = {}; ExternalImageMetadata metadata;
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer; AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
if (__builtin_available(android 26, *)) { if (__builtin_available(android 26, *)) {
AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_Desc bufferDesc;
@@ -206,29 +249,16 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImag
metadata.width = bufferDesc.width; metadata.width = bufferDesc.width;
metadata.height = bufferDesc.height; metadata.height = bufferDesc.height;
metadata.layers = bufferDesc.layers; metadata.layers = bufferDesc.layers;
metadata.isProtected = isProtectedFromUsage(bufferDesc.usage);
std::tie(metadata.format, metadata.usage) = std::tie(metadata.format, metadata.usage) =
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB); getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
std::tie(metadata.filamentFormat, metadata.filamentUsage) =
getFilamentFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
if (isProtectedFromUsage(bufferDesc.usage)) {
metadata.filamentUsage |= TextureUsage::PROTECTED;
}
// TODO: The following seems unnecessary. we should be able to discern directly from the
// bufferDesc.
if (any(metadata.filamentUsage & TextureUsage::BLIT_SRC)) {
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
if (any(metadata.filamentUsage & (TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE))) {
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
} }
metadata.samples = VK_SAMPLE_COUNT_1_BIT; metadata.samples = VK_SAMPLE_COUNT_1_BIT;
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = { VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID, .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
.pNext = nullptr,
}; };
VkAndroidHardwareBufferPropertiesANDROID properties = { VkAndroidHardwareBufferPropertiesANDROID properties = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID, .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
@@ -238,155 +268,138 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::extractExternalImag
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkGetAndroidHardwareBufferProperties failed with error=" << "vkGetAndroidHardwareBufferProperties failed with error="
<< static_cast<int32_t>(result); << static_cast<int32_t>(result);
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB); VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat) FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
<< "mismatched image format( " << metadata.format << ") and queried format(" << "mismatched image format( " << metadata.format << ") and queried format("
<< bufferPropertiesFormat << ") for external image (AHB)"; << bufferPropertiesFormat << ") for external image (AHB)";
metadata.externalFormat = formatInfo.externalFormat;
bool const requiresConversion =
metadata.format == VK_FORMAT_UNDEFINED ||
fvkutils::isVKYcbcrConversionFormat(metadata.format);
if (requiresConversion) {
metadata.format = VK_FORMAT_UNDEFINED;
metadata.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
metadata.externalFormat = formatInfo.externalFormat;
} else {
metadata.externalFormat = 0;
}
metadata.allocationSize = properties.allocationSize; metadata.allocationSize = properties.allocationSize;
metadata.memoryTypeBits = properties.memoryTypeBits; metadata.memoryTypeBits = properties.memoryTypeBits;
metadata.ycbcrConversionComponents = formatInfo.samplerYcbcrConversionComponents;
metadata.ycbcrModel = formatInfo.suggestedYcbcrModel;
metadata.ycbcrRange = formatInfo.suggestedYcbcrRange;
metadata.xChromaOffset = formatInfo.suggestedXChromaOffset;
metadata.yChromaOffset = formatInfo.suggestedYChromaOffset;
return metadata; return metadata;
} }
VulkanPlatform::ImageData VulkanPlatformAndroid::createVkImageFromExternal( VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
ExternalImageHandleRef externalImage) const { ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
auto metadata = extractExternalImageMetadata(externalImage); uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
auto const* fvkExternalImage = auto const* fvkExternalImage =
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get()); static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer; ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
memoryTypeIndex, usage);
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
return data;
}
VkDevice const device = getDevice(); VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, SamplerYcbcrConversion chroma,
VkPhysicalDevice const physicalDevice = getPhysicalDevice(); uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
auto buildImage = [&](ExternalImageMetadata const& metadata) { VkImageViewType viewType, VkComponentMapping swizzle){
bool const isExternal = metadata.externalFormat != 0; VkExternalFormatANDROID externalFormat = {
VkExternalFormatANDROID const externalFormat = { .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, .externalFormat = internalFormat,
.pNext = nullptr,
.externalFormat = metadata.externalFormat,
};
VkExternalMemoryImageCreateInfo externalCreateInfo = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = isExternal ? &externalFormat : nullptr,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
};
VkFormat formats[2] = {};
VkImageFormatListCreateInfo imageFormatListInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
.pNext = nullptr,
.viewFormatCount = 2,
.pViewFormats = formats,
};
if (fvkExternalImage->sRGB) {
formats[0] = metadata.format;
formats[1] = transformVkFormat(metadata.format, /*sRGB=*/false);
imageFormatListInfo.pNext = externalCreateInfo.pNext;
externalCreateInfo.pNext = &imageFormatListInfo;
}
VkImageCreateInfo const imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &externalCreateInfo,
.flags = fvkExternalImage->sRGB ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0u,
.imageType = VK_IMAGE_TYPE_2D,
// For non external images, use the same format as the AHB, which isn't in SRGB
// Fix VUID-VkMemoryAllocateInfo-pNext-02387
.format = transformVkFormat(metadata.format, /*sRGB=*/false),
.extent = {
metadata.width,
metadata.height,
1u,
},
.mipLevels = 1,
.arrayLayers = metadata.layers,
.samples = metadata.samples,
.usage = metadata.usage,
};
VkImage image;
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &image);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
return image;
}; };
auto allocMem = [&](VkImage image, ExternalImageMetadata const& metadata) { TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
bool const isExternal = metadata.externalFormat != 0; VkSamplerYcbcrConversionCreateInfo conversionInfo = {
// Allocate the memory .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
VkImportAndroidHardwareBufferInfoANDROID const androidHardwareBufferInfo = { .pNext = &externalFormat,
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID, .format = VK_FORMAT_UNDEFINED,
.buffer = buffer, .ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
}; .ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
VkMemoryDedicatedAllocateInfo const memoryDedicatedAllocateInfo = { .components = fvkutils::getSwizzleMap(swizzleArray),
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, .xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
.pNext = &androidHardwareBufferInfo, .yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
.image = image, .chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
.buffer = VK_NULL_HANDLE, };
}; VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
VkPhysicalDeviceMemoryProperties memoryProperties; VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties); nullptr, &conversion);
VkMemoryPropertyFlags requiredMemoryFlags = FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
!isExternal && any(metadata.filamentUsage & TextureUsage::UPLOADABLE) << "Unable to create Ycbcr Conversion."
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT << " error=" << static_cast<int32_t>(result);
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
if (any(metadata.filamentUsage & TextureUsage::PROTECTED)) { VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
requiredMemoryFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT; .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
} .conversion = conversion,
uint32_t const memoryTypeIndex = VulkanContext::selectMemoryType(memoryProperties,
metadata.memoryTypeBits, requiredMemoryFlags);
VkMemoryAllocateInfo const allocInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &memoryDedicatedAllocateInfo,
.allocationSize = metadata.allocationSize,
.memoryTypeIndex = memoryTypeIndex,
};
VkDeviceMemory memory;
VkResult result = vkAllocateMemory(device, &allocInfo, VKALLOC, &memory);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
result = vkBindImageMemory(getDevice(), image, memory, 0);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
return memory;
}; };
VulkanPlatform::ImageData::Bundle internal = {}, external = {}; VkImageViewCreateInfo viewInfo = {
auto img = buildImage(metadata); .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
auto mem = allocMem(img, metadata); .pNext = &samplerYcbcrConversionInfo,
.flags = 0,
// Note that we're always choosing a non-externally sampled format if it exists. .image = image,
if (metadata.externalFormat == 0) { .viewType = viewType,
internal = { img, mem }; .format = VK_FORMAT_UNDEFINED,
} else { .components = swizzle,
external = { img, mem }; .subresourceRange = range,
}
return {
.internal = internal,
.external = external,
}; };
VkImageView imageView;
result = vkCreateImageView(device, &viewInfo, VKALLOC, &imageView);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "Unable to create VkImageView."
<< " error=" << static_cast<int32_t>(result);
return imageView;
}
VkSampler VulkanPlatform::createExternalSamplerImpl(
VkDevice device, SamplerYcbcrConversion chroma, SamplerParams params,
uint32_t internalFormat) {
VkExternalFormatANDROID externalFormat = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
.externalFormat = internalFormat,
};
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.pNext = &externalFormat,
.format = VK_FORMAT_UNDEFINED,
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
.components = fvkutils::getSwizzleMap(swizzleArray),
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
};
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
nullptr, &conversion);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "Unable to create Ycbcr Conversion."
<< " error=" << static_cast<int32_t>(result);
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
.pNext = nullptr,
.conversion = conversion,
};
VkSamplerCreateInfo samplerInfo = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = &samplerYcbcrConversionInfo,
.magFilter = fvkutils::getFilter(params.filterMag),
.minFilter = fvkutils::getFilter(params.filterMin),
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
.addressModeU = fvkutils::getWrapMode(params.wrapS),
.addressModeV = fvkutils::getWrapMode(params.wrapT),
.addressModeW = fvkutils::getWrapMode(params.wrapR),
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
.compareOp = fvkutils::getCompareOp(params.compareFunc),
.minLod = 0.0f,
.maxLod = fvkutils::getMaxLod(params.filterMin),
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
};
VkSampler sampler;
result = vkCreateSampler(device, &samplerInfo, VKALLOC, &sampler);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "Unable to create sampler."
<< " error=" << static_cast<int32_t>(result);
return sampler;
} }
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const { VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
@@ -400,7 +413,7 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
VkSurfaceKHR surface; VkSurfaceKHR surface;
VkExtent2D extent; VkExtent2D extent;
VkAndroidSurfaceCreateInfoKHR const createInfo = { VkAndroidSurfaceCreateInfoKHR const createInfo{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.window = (ANativeWindow*) nativeWindow, .window = (ANativeWindow*) nativeWindow,
}; };
@@ -414,9 +427,20 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
// Deprecated platform dependent helper methods // Deprecated platform dependent helper methods
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; } VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; }
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
ExternalImageHandleRef externalImage, VkDevice device) {
return ExternalImageMetadata{};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
ExternalImageHandleRef externalImage, VkDevice device,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
return ImageData{};
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow, VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept { VkInstance instance, uint64_t flags) noexcept {
return SurfaceBundle{}; return SurfaceBundle{};
} }
} // namespace filament::backend }// namespace filament::backend
@@ -43,6 +43,30 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
return ret; return ret;
} }
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
ExternalImageHandleRef externalImage, VkDevice device) {
return {};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
ExternalImageHandleRef externalImage, VkDevice device,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
return {};
}
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
SamplerYcbcrConversion chroma,
SamplerParams sampler,
uint32_t internalFormat) {
return VK_NULL_HANDLE;
}
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
return VK_NULL_HANDLE;
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow, VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept { VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface; VkSurfaceKHR surface;
@@ -84,6 +84,30 @@ using namespace bluevk;
namespace filament::backend { namespace filament::backend {
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
ExternalImageHandleRef externalImage, VkDevice device) {
return {};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
ExternalImageHandleRef externalImage, VkDevice device,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
return {};
}
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
SamplerYcbcrConversion chroma,
SamplerParams sampler,
uint32_t internalFormat) {
return VK_NULL_HANDLE;
}
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
return VK_NULL_HANDLE;
}
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
VulkanPlatform::ExtensionSet const ret = { VulkanPlatform::ExtensionSet const ret = {
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND) #if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
@@ -51,8 +51,6 @@ VkFormat getVkFormat(ElementType type, bool normalized, bool integer) {
return VK_FORMAT_UNDEFINED; return VK_FORMAT_UNDEFINED;
} }
} }
// Non-normalized case
switch (type) { switch (type) {
// Single Component Types // Single Component Types
case ElementType::BYTE: return integer ? VK_FORMAT_R8_SINT : VK_FORMAT_R8_SSCALED; case ElementType::BYTE: return integer ? VK_FORMAT_R8_SINT : VK_FORMAT_R8_SSCALED;
@@ -184,46 +184,6 @@ bool isVkStencilFormat(VkFormat format) {
return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
} }
bool isVKYcbcrConversionFormat(VkFormat format) {
switch (format) {
case VK_FORMAT_G8B8G8R8_422_UNORM:
case VK_FORMAT_B8G8R8G8_422_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G16B16G16R16_422_UNORM:
case VK_FORMAT_B16G16R16G16_422_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
return true;
default:
return false;
}
}
static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); } static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); }
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) { uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
@@ -98,8 +98,6 @@ bool isVkDepthFormat(VkFormat format);
bool isVkStencilFormat(VkFormat format); bool isVkStencilFormat(VkFormat format);
bool isVKYcbcrConversionFormat(VkFormat format);
VkImageAspectFlags getImageAspect(VkFormat format); VkImageAspectFlags getImageAspect(VkFormat format);
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask); uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask);
File diff suppressed because it is too large Load Diff
+56 -109
View File
@@ -27,7 +27,6 @@
#include <webgpu/webgpu_cpp.h> #include <webgpu/webgpu_cpp.h>
#include <algorithm>
#include <sstream> #include <sstream>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
@@ -67,123 +66,71 @@ 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,
wgpu::Instance instance = device.GetAdapter().GetInstance(); [&descriptor](auto const& status, wgpu::CompilationInfo const* info) {
instance.WaitAny( switch (status) {
module.GetCompilationInfo(wgpu::CallbackMode::WaitAnyOnly, case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
[&descriptor](auto const& status, FWGPU_LOGW << "Shader compilation info callback cancelled for "
wgpu::CompilationInfo const* info) { << descriptor.label << "?" << utils::io::endl;
switch (status) { return;
case wgpu::CompilationInfoRequestStatus::CallbackCancelled: case wgpu::CompilationInfoRequestStatus::Success:
FWGPU_LOGW << "Shader compilation info callback cancelled for " break;
<< descriptor.label << "?" << utils::io::endl; }
return; if (info != nullptr) {
case wgpu::CompilationInfoRequestStatus::Success: std::stringstream errorStream;
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) { }
std::stringstream errorStream; FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
int errorCount = 0; << errorCount << " error(s) compiling " << descriptor.label << ":\n"
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) { << errorStream.str();
wgpu::CompilationMessage const& message = info->messages[msgIndex]; }
switch (message.type) { FWGPU_LOGD << descriptor.label << " compiled successfully" << utils::io::endl;
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;
} }
// This is a 1 to 1 mapping of the ReservedSpecializationConstants enum in EngineEnums.h
// The _hack is a workaround until https://issues.chromium.org/issues/42250586 is resolved
// This workaround is the same one being used on the generateSpecializationConstant() function
wgpu::StringView getSpecConstantStringId(uint32_t id) {
switch (id) {
case 0:
return "0";// BACKEND_FEATURE_LEVEL_hack
case 1:
return "1";// CONFIG_MAX_INSTANCES_hack
case 2:
return "2";// ONFIG_STATIC_TEXTURE_TARGET_WORKAROUND_hack
case 3:
return "3";// CONFIG_SRGB_SWAPCHAIN_EMULATION_hack
case 4:
return "4";// CONFIG_FROXEL_BUFFER_HEIGHT_hack
case 5:
return "5";// CONFIG_POWER_VR_SHADER_WORKAROUNDS_hack
case 6:
return "6";// CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP_hack
case 7:
return "7";// CONFIG_DEBUG_FROXEL_VISUALIZATION_hack
case 8:
return "8";// CONFIG_STEREO_EYE_COUNT_hack
case 9:
return "9";// CONFIG_SH_BANDS_COUNT_hack
case 10:
return "10";// CONFIG_SHADOW_SAMPLING_METHOD_hack
default:
PANIC_POSTCONDITION("Unknown/unhandled spec constant key/id: %d", id);
}
}
std::vector<wgpu::ConstantEntry> convertConstants( std::vector<wgpu::ConstantEntry> convertConstants(
utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const& utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const&
constantsInfo) { constantsInfo) {
std::vector<wgpu::ConstantEntry> constants; std::vector<wgpu::ConstantEntry> constants(constantsInfo.size());
constants.reserve(constantsInfo.size()); for (size_t i = 0; i < constantsInfo.size(); i++) {
for (filament::backend::Program::SpecializationConstant const& constant: constantsInfo) { filament::backend::Program::SpecializationConstant const& specConstant = constantsInfo[i];
// CONFIG_MAX_INSTANCES (1) and CONFIG_FROXEL_BUFFER_HEIGHT (4) will not be present wgpu::ConstantEntry& constantEntry = constants[i];
// as constant overrides in the generated WGSL, because WGSL doesn't support specialization constantEntry.key = wgpu::StringView(std::to_string(specConstant.id));
// constants as an array length if (auto* v = std::get_if<int32_t>(&specConstant.value)) {
// More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005 constantEntry.value = static_cast<double>(*v);
// CONFIG_SRGB_SWAPCHAIN_EMULATION (3) is being skipped all together since it's only } else if (auto* f = std::get_if<float>(&specConstant.value)) {
// included for the case of mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0, which should constantEntry.value = static_cast<double>(*f);
// not be possible for WebGPU } else if (auto* b = std::get_if<bool>(&specConstant.value)) {
if (constant.id == 1 || constant.id == 3 || constant.id == 4) { constantEntry.value = *b ? 0.0 : 1.0;
continue;
} }
double value = 0.0;
if (auto* v = std::get_if<int32_t>(&constant.value)) {
value = static_cast<double>(*v);
} else if (auto* f = std::get_if<float>(&constant.value)) {
value = static_cast<double>(*f);
} else if (auto* b = std::get_if<bool>(&constant.value)) {
value = *b ? 0.0 : 1.0;
}
constants.push_back(
wgpu::ConstantEntry{ .key = getSpecConstantStringId(constant.id), .value = value });
} }
return constants; return constants;
} }
+65 -363
View File
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <utils/Hash.h>
#include "webgpu/WebGPUDriver.h" #include "webgpu/WebGPUDriver.h"
#include "WebGPUPipelineCreation.h"
#include "WebGPUSwapChain.h" #include "WebGPUSwapChain.h"
#include "webgpu/WebGPUConstants.h"
#include <backend/platforms/WebGPUPlatform.h> #include <backend/platforms/WebGPUPlatform.h>
#include "CommandStreamDispatcher.h" #include "CommandStreamDispatcher.h"
@@ -25,20 +25,18 @@
#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>
@@ -186,6 +184,8 @@ void printAdapterDetails(wgpu::Adapter const& adapter) {
} }
#endif #endif
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) #if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
void printDeviceDetails(wgpu::Device const& device) { void printDeviceDetails(wgpu::Device const& device) {
wgpu::SupportedFeatures supportedFeatures{}; wgpu::SupportedFeatures supportedFeatures{};
@@ -237,7 +237,6 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfi
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) #if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printDeviceDetails(mDevice); printDeviceDetails(mDevice);
#endif #endif
mQueue = mDevice.GetQueue();
} }
WebGPUDriver::~WebGPUDriver() noexcept = default; WebGPUDriver::~WebGPUDriver() noexcept = default;
@@ -292,22 +291,7 @@ void WebGPUDriver::endFrame(uint32_t frameId) {
void WebGPUDriver::flush(int) { void WebGPUDriver::flush(int) {
} }
void WebGPUDriver::finish(int /* dummy */) { void WebGPUDriver::finish(int) {
if (mCommandEncoder != nullptr) {
// submit the command buffer thus far...
assert_invariant(mRenderPassEncoder == nullptr);
wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "command_buffer",
};
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
assert_invariant(mCommandBuffer);
mQueue.Submit(1, &mCommandBuffer);
mCommandBuffer = nullptr;
// create a new command buffer encoder to continue recording the next command for frame...
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = { .label = "command_encoder" };
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
assert_invariant(mCommandEncoder);
}
} }
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) { void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
@@ -335,9 +319,6 @@ void WebGPUDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
} }
void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) { void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
if (boh) {
destructHandle<WGPUBufferObject>(boh);
}
} }
void WebGPUDriver::destroyTexture(Handle<HwTexture> th) { void WebGPUDriver::destroyTexture(Handle<HwTexture> th) {
@@ -372,9 +353,6 @@ void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh)
} }
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) { void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
if (tqh) {
destructHandle<WebGPUDescriptorSet>(tqh);
}
} }
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept { Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
@@ -389,7 +367,9 @@ Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
return allocHandle<WGPUTexture>(); return allocHandle<WGPUTexture>();
} }
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept { return allocHandle<WGPUTexture>(); } Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
}
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept { Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
return allocHandle<WGPUProgram>(); return allocHandle<WGPUProgram>();
@@ -408,7 +388,7 @@ Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
} }
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept { Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
return allocHandle<WGPUTexture>(); return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
} }
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept { Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
@@ -424,7 +404,7 @@ Handle<HwVertexBuffer> WebGPUDriver::createVertexBufferS() noexcept {
} }
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept { Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
return allocHandle<WebGPUDescriptorSet>(); return Handle<HwDescriptorSet>((Handle<HwDescriptorSet>::HandleId) mNextFakeHandle++);
} }
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept { Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
@@ -436,7 +416,7 @@ Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
} }
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept { Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
return allocHandle<WGPUTexture>(); return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
} }
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept { Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
@@ -448,15 +428,15 @@ Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcep
} }
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept { Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
return allocHandle<WGPUTexture>(); return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
} }
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept { Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
return allocHandle<WGPUTexture>(); return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
} }
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept { Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
return allocHandle<WGPUTexture>(); return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
} }
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) { void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
@@ -464,12 +444,11 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
assert_invariant(!mSwapChain); assert_invariant(!mSwapChain);
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags); wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
mQueue = mDevice.GetQueue();
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow); wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter, mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
mDevice, flags); mDevice, flags);
assert_invariant(mSwapChain); assert_invariant(mSwapChain);
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
mSwapChain->getColorFormat());
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only " FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
"background components have been instantiated/selected, such as surface/screen, " "background components have been instantiated/selected, such as surface/screen, "
"graphics device/GPU, etc.), thus nothing is being drawn to the screen." "graphics device/GPU, etc.), thus nothing is being drawn to the screen."
@@ -488,82 +467,46 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
uint32_t height, uint64_t flags) {} uint32_t height, uint64_t flags) {}
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount, void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes) { uint8_t attributeCount, AttributeArray attributes) {}
constructHandle<WGPUVertexBufferInfo>(vbih, bufferCount, attributeCount, attributes);
}
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount, void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih) { Handle<HwVertexBufferInfo> vbih) {}
auto* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(vbih);
constructHandle<WGPUVertexBuffer>(vbh, mDevice, vertexCount, vertexBufferInfo->bufferCount,
vbih);
}
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType, void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage) { uint32_t indexCount, BufferUsage usage) {}
auto elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
constructHandle<WGPUIndexBuffer>(ibh, mDevice, elementSize, indexCount);
}
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount, void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage) { BufferObjectBinding bindingType, BufferUsage usage) {}
constructHandle<WGPUBufferObject>(boh, mDevice, bindingType, byteCount);
}
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) {}
assert_invariant(mDevice);
auto* renderPrimitive = constructHandle<WGPURenderPrimitive>(rph);
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
auto* indexBuffer = handleCast<WGPUIndexBuffer>(ibh);
renderPrimitive->vertexBuffer = vertexBuffer;
renderPrimitive->indexBuffer = indexBuffer;
renderPrimitive->type = pt;
}
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) { void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
constructHandle<WGPUProgram>(ph, mDevice, program); constructHandle<WGPUProgram>(ph, mDevice, program);
@@ -589,10 +532,7 @@ void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
} }
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh, void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh) { Handle<HwDescriptorSetLayout> dslh) {}
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getBindGroupEntries());
}
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) { Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
return {}; return {};
@@ -628,11 +568,11 @@ 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 WGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined; return true;
} }
bool WebGPUDriver::isTextureSwizzleSupported() { bool WebGPUDriver::isTextureSwizzleSupported() {
return false; return true;
} }
bool WebGPUDriver::isTextureFormatMipmappable(TextureFormat format) { bool WebGPUDriver::isTextureFormatMipmappable(TextureFormat format) {
@@ -721,21 +661,20 @@ size_t WebGPUDriver::getMaxArrayTextureLayers() {
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t byteOffset) { uint32_t byteOffset) {
updateGPUBuffer(handleCast<WGPUIndexBuffer>(ibh), std::move(p), byteOffset); scheduleDestroy(std::move(p));
} }
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p, void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
uint32_t byteOffset) { uint32_t byteOffset) {
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset); scheduleDestroy(std::move(p));
} }
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh, void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
BufferDescriptor&& p, uint32_t byteOffset) { uint32_t byteOffset) {
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset); scheduleDestroy(std::move(p));
} }
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) { void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
// Is there something that needs to be done here? Vulkan has left it unimplemented.
} }
void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index, void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
@@ -743,8 +682,7 @@ void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh); auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
auto* bufferObject = handleCast<WGPUBufferObject>(boh); auto* bufferObject = handleCast<WGPUBufferObject>(boh);
assert_invariant(index < vertexBuffer->buffers.size()); assert_invariant(index < vertexBuffer->buffers.size());
assert_invariant(bufferObject->buffer.GetUsage() & wgpu::BufferUsage::Vertex); vertexBuffer->setBuffer(bufferObject, index);
vertexBuffer->buffers[index] = bufferObject->buffer;
} }
void WebGPUDriver::update3DImage(Handle<HwTexture> th, void WebGPUDriver::update3DImage(Handle<HwTexture> th,
@@ -776,31 +714,12 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
} }
} }
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) { void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
assert_invariant(mCommandEncoder); wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
.label = "command_encoder"
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
// if (renderTarget == mDefaultRenderTarget) {
// FWGPU_LOGW << "Default render target"
// << utils::io::endl;
// } else {
// FWGPU_LOGW << "Non Default render target"
// << utils::io::endl;
// }
wgpu::RenderPassDescriptor renderPassDescriptor2;
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
.view = mSwapChain->getDepthTextureView(),
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
.depthClearValue = static_cast<float>(params.clearDepth),
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
.stencilClearValue = params.clearStencil,
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
}; };
renderTarget->setUpRenderPassAttachments(renderPassDescriptor2, mTextureView, params); mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
renderPassDescriptor2.depthStencilAttachment = &depthStencilAttachment; assert_invariant(mCommandEncoder);
// TODO: Remove this code once WebGPU pipeline is implemented // TODO: Remove this code once WebGPU pipeline is implemented
static float red = 1.0f; static float red = 1.0f;
if (red - 0.01 > 0) { if (red - 0.01 > 0) {
@@ -825,14 +744,19 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams
.timestampWrites = nullptr, .timestampWrites = nullptr,
}; };
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor2); mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom, mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far); params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
} }
void WebGPUDriver::endRenderPass(int /* dummy */) { void WebGPUDriver::endRenderPass(int) {
mRenderPassEncoder.End(); mRenderPassEncoder.End();
mRenderPassEncoder = nullptr; mRenderPassEncoder = nullptr;
wgpu::CommandBufferDescriptor commandBufferDescriptor {
.label = "command_buffer",
};
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
assert_invariant(mCommandBuffer);
} }
void WebGPUDriver::nextSubpass(int) { void WebGPUDriver::nextSubpass(int) {
@@ -847,19 +771,9 @@ void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow); wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize); mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize);
assert_invariant(mTextureView); assert_invariant(mTextureView);
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
.label = "command_encoder"
};
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
assert_invariant(mCommandEncoder);
} }
void WebGPUDriver::commit(Handle<HwSwapChain> sch) { void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "command_buffer",
};
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
assert_invariant(mCommandBuffer);
mCommandEncoder = nullptr; mCommandEncoder = nullptr;
mQueue.Submit(1, &mCommandBuffer); mQueue.Submit(1, &mCommandBuffer);
mCommandBuffer = nullptr; mCommandBuffer = nullptr;
@@ -916,83 +830,16 @@ void WebGPUDriver::blit(
} }
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) { void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
// TODO Investigate implications of this hash more closely. Vulkan has a whole class
// VulkanPipelineCache to handle this, may be missing nuance
static auto pipleineStateHasher = utils::hash::MurmurHashFn<filament::backend::PipelineState>();
auto hash = pipleineStateHasher(pipelineState);
if(mPipelineMap.find(hash) != mPipelineMap.end()){
mRenderPassEncoder.SetPipeline(mPipelineMap[hash]);
return;
}
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());
mPipelineMap[hash] = pipeline;
mRenderPassEncoder.SetPipeline(pipeline);
} }
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) { void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
auto* renderPrimitive = handleCast<WGPURenderPrimitive>(rph);
// This *must* match the WGPUVertexBufferInfo that was bound in bindPipeline(). But we want
// to allow to call this before bindPipeline(), so the validation can only happen in draw()
auto vbi = handleCast<WGPUVertexBufferInfo>(renderPrimitive->vertexBuffer->vbih);
assert_invariant(
vbi->getVertexBufferLayoutSize() == renderPrimitive->vertexBuffer->buffers.size());
for (uint32_t i = 0; i < vbi->getVertexBufferLayoutSize(); i++) {
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
}
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->buffer,
renderPrimitive->indexBuffer->indexFormat);
} }
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) { void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
// Calling DrawIndexed with "firstInstance = 0" results in a NON spinning triangle
// mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
// Calling DrawIndexed with "firstInstance = 1" results in a spinning triangle
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 1);
// Calling Draw with "firstInstance = 0" results in a NON spinning triangle
// Calling Draw with "firstInstance = 1" results in a spinning triangle
// mRenderPassEncoder.Draw(indexCount, instanceCount, 0, 1);
} }
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset, void WebGPUDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
uint32_t indexCount, uint32_t instanceCount) { uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
draw2(indexOffset, indexCount, instanceCount);
} }
void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) { void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
@@ -1011,173 +858,28 @@ void WebGPUDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
void WebGPUDriver::resetState(int) { void WebGPUDriver::resetState(int) {
} }
void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh, void WebGPUDriver::updateDescriptorSetBuffer(
backend::descriptor_binding_t binding, Handle<HwBufferObject> boh, uint32_t offset, Handle<HwDescriptorSet> dsh,
backend::descriptor_binding_t binding,
Handle<HwBufferObject> boh,
uint32_t offset,
uint32_t size) { uint32_t size) {
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
auto buffer = handleCast<WGPUBufferObject>(boh);
if (!bindGroup->getIsLocked()) {
// TODO making assumptions that size and offset mean the same thing here.
wgpu::BindGroupEntry entry{ .binding = static_cast<uint32_t>(binding * 2),
.buffer = buffer->buffer,
.offset = offset,
.size = size };
bindGroup->addEntry(entry.binding, std::move(entry));
}
} }
void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> dsh, void WebGPUDriver::updateDescriptorSetTexture(
backend::descriptor_binding_t binding, Handle<HwTexture> th, SamplerParams params) { Handle<HwDescriptorSet> dsh,
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh); backend::descriptor_binding_t binding,
auto texture = handleCast<WGPUTexture>(th); Handle<HwTexture> th,
SamplerParams params) {
if (!bindGroup->getIsLocked()) {
// Dawn will cache duplicate samplers, so we don't strictly need to maintain a cache.
// Making a cache might save us minor perf by reducing param translation
auto sampler = makeSampler(params);
// TODO making assumptions that size and offset mean the same thing here.
wgpu::BindGroupEntry tEntry{ .binding = static_cast<uint32_t>(binding * 2),
.textureView = texture->getTexView() };
bindGroup->addEntry(tEntry.binding, std::move(tEntry));
wgpu::BindGroupEntry sEntry{ .binding = static_cast<uint32_t>(binding * 2 + 1),
.sampler = sampler };
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
}
} }
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh, void WebGPUDriver::bindDescriptorSet(
backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) { Handle<HwDescriptorSet> dsh,
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh); backend::descriptor_set_t set,
const auto wbg = bindGroup->lockAndReturn(mDevice); backend::DescriptorSetOffsetArray&& offsets) {
assert_invariant(mRenderPassEncoder);
// TODO is this how we should be getting the dynamic offsets?
// should we add offsets for unused entries or is the input already have them?
// this implementation assumes unused entries are not provided, and adds dummy values.
// The count also includes unused entities, as not doing so produces errors
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
uint32_t const* const dynamicOffsetsWithUnused = bindGroup->setDynamicOffsets(offsets.data());
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, dynamicOffsetsWithUnused);
} }
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
} }
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
wgpu::SamplerDescriptor desc;
desc.label = "TODO";
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
switch (params.filterMag) {
case SamplerMagFilter::NEAREST: {
desc.magFilter = wgpu::FilterMode::Nearest;
break;
}
case SamplerMagFilter::LINEAR: {
desc.magFilter = wgpu::FilterMode::Linear;
break;
}
}
switch (params.filterMin) {
case SamplerMinFilter::NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
}
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
}
}
switch (params.compareFunc) {
case SamplerCompareFunc::LE: {
desc.compare = wgpu::CompareFunction::LessEqual;
break;
}
case SamplerCompareFunc::GE: {
desc.compare = wgpu::CompareFunction::GreaterEqual;
break;
}
case SamplerCompareFunc::L: {
desc.compare = wgpu::CompareFunction::Less;
break;
}
case SamplerCompareFunc::G: {
desc.compare = wgpu::CompareFunction::Greater;
break;
}
case SamplerCompareFunc::E: {
desc.compare = wgpu::CompareFunction::Equal;
break;
}
case SamplerCompareFunc::NE: {
desc.compare = wgpu::CompareFunction::NotEqual;
break;
}
case SamplerCompareFunc::A: {
desc.compare = wgpu::CompareFunction::Always;
break;
}
case SamplerCompareFunc::N: {
desc.compare = wgpu::CompareFunction::Never;
break;
}
}
desc.maxAnisotropy = 1u << params.anisotropyLog2;
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
//TODO Once we can properly map to descriptorsetlayout use the sampler.
return mDevice.CreateSampler(/*&desc*/);
}
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
switch (fWrapMode) {
case SamplerWrapMode::CLAMP_TO_EDGE: {
return wgpu::AddressMode::ClampToEdge;
break;
}
case SamplerWrapMode::REPEAT: {
return wgpu::AddressMode::Repeat;
break;
}
case SamplerWrapMode::MIRRORED_REPEAT: {
return wgpu::AddressMode::MirrorRepeat;
break;
}
}
return wgpu::AddressMode::Undefined;
}
} // namespace filament } // namespace filament

Some files were not shown because too many files have changed in this diff Show More