Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
031cd302dd |
+66
-66
@@ -40,20 +40,20 @@ inside the Filament source tree.
|
|||||||
|
|
||||||
To trigger an incremental debug build:
|
To trigger an incremental debug build:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh debug
|
$ ./build.sh debug
|
||||||
```
|
```
|
||||||
|
|
||||||
To trigger an incremental release build:
|
To trigger an incremental release build:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh release
|
$ ./build.sh release
|
||||||
```
|
```
|
||||||
|
|
||||||
To trigger both incremental debug and release builds:
|
To trigger both incremental debug and release builds:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh debug release
|
$ ./build.sh debug release
|
||||||
```
|
```
|
||||||
|
|
||||||
To install the libraries and executables in `out/debug/` and `out/release/`, add the `-i` flag.
|
To install the libraries and executables in `out/debug/` and `out/release/`, add the `-i` flag.
|
||||||
@@ -76,9 +76,9 @@ The following CMake options are boolean options specific to Filament:
|
|||||||
|
|
||||||
To turn an option on or off:
|
To turn an option on or off:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cd <cmake-build-directory>
|
$ cd <cmake-build-directory>
|
||||||
cmake . -DOPTION=ON # Replace OPTION with the option name, set to ON / OFF
|
$ cmake . -DOPTION=ON # Replace OPTION with the option name, set to ON / OFF
|
||||||
```
|
```
|
||||||
|
|
||||||
Options can also be set with the CMake GUI.
|
Options can also be set with the CMake GUI.
|
||||||
@@ -102,38 +102,38 @@ script.
|
|||||||
If you'd like to run `cmake` directly rather than using the build script, it can be invoked as
|
If you'd like to run `cmake` directly rather than using the build script, it can be invoked as
|
||||||
follows, with some caveats that are explained further down.
|
follows, with some caveats that are explained further down.
|
||||||
|
|
||||||
```shell
|
```
|
||||||
mkdir out/cmake-release
|
$ mkdir out/cmake-release
|
||||||
cd out/cmake-release
|
$ cd out/cmake-release
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
||||||
```
|
```
|
||||||
|
|
||||||
Your Linux distribution might default to `gcc` instead of `clang`, if that's the case invoke
|
Your Linux distribution might default to `gcc` instead of `clang`, if that's the case invoke
|
||||||
`cmake` with the following command:
|
`cmake` with the following command:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
mkdir out/cmake-release
|
$ mkdir out/cmake-release
|
||||||
cd out/cmake-release
|
$ cd out/cmake-release
|
||||||
# Or use a specific version of clang, for instance /usr/bin/clang-14
|
# Or use a specific version of clang, for instance /usr/bin/clang-14
|
||||||
CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS=-stdlib=libc++ \
|
$ CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS=-stdlib=libc++ \
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also export the `CC` and `CXX` environment variables to always point to `clang`. Another
|
You can also export the `CC` and `CXX` environment variables to always point to `clang`. Another
|
||||||
solution is to use `update-alternatives` to both change the default compiler, and point to a
|
solution is to use `update-alternatives` to both change the default compiler, and point to a
|
||||||
specific version of clang:
|
specific version of clang:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 100
|
$ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 100
|
||||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-14 100
|
$ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-14 100
|
||||||
update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100
|
$ update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100
|
||||||
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
|
$ update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, invoke `ninja`:
|
Finally, invoke `ninja`:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
ninja
|
$ ninja
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build Filament, its tests and samples, and various host tools.
|
This will build Filament, its tests and samples, and various host tools.
|
||||||
@@ -143,8 +143,8 @@ This will build Filament, its tests and samples, and various host tools.
|
|||||||
To compile Filament you must have the most recent version of Xcode installed and you need to
|
To compile Filament you must have the most recent version of Xcode installed and you need to
|
||||||
make sure the command line tools are setup by running:
|
make sure the command line tools are setup by running:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
xcode-select --install
|
$ xcode-select --install
|
||||||
```
|
```
|
||||||
|
|
||||||
If you wish to run the Vulkan backend instead of the default Metal backend, you must install
|
If you wish to run the Vulkan backend instead of the default Metal backend, you must install
|
||||||
@@ -152,11 +152,11 @@ the LunarG SDK, enable "System Global Components", and reboot your machine.
|
|||||||
|
|
||||||
Then run `cmake` and `ninja` to trigger a build:
|
Then run `cmake` and `ninja` to trigger a build:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
mkdir out/cmake-release
|
$ mkdir out/cmake-release
|
||||||
cd out/cmake-release
|
$ cd out/cmake-release
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
|
||||||
ninja
|
$ ninja
|
||||||
```
|
```
|
||||||
|
|
||||||
### iOS
|
### iOS
|
||||||
@@ -164,8 +164,8 @@ ninja
|
|||||||
The easiest way to build Filament for iOS is to use `build.sh` and the
|
The easiest way to build Filament for iOS is to use `build.sh` and the
|
||||||
`-p ios` flag. For instance to build the debug target:
|
`-p ios` flag. For instance to build the debug target:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh -p ios debug
|
$ ./build.sh -p ios debug
|
||||||
```
|
```
|
||||||
|
|
||||||
See [ios/samples/README.md](./ios/samples/README.md) for more information.
|
See [ios/samples/README.md](./ios/samples/README.md) for more information.
|
||||||
@@ -191,10 +191,10 @@ using `fsutil.exe file queryCaseSensitiveInfo`.
|
|||||||
Next, open `x64 Native Tools Command Prompt for VS 2019`, create a working directory, and run
|
Next, open `x64 Native Tools Command Prompt for VS 2019`, create a working directory, and run
|
||||||
CMake in it:
|
CMake in it:
|
||||||
|
|
||||||
```bat
|
```
|
||||||
mkdir out
|
> mkdir out
|
||||||
cd out
|
> cd out
|
||||||
cmake ..
|
> cmake ..
|
||||||
```
|
```
|
||||||
|
|
||||||
Open the generated solution file `TNT.sln` in Visual Studio.
|
Open the generated solution file `TNT.sln` in Visual Studio.
|
||||||
@@ -204,15 +204,15 @@ target in the _Solution Explorer_ and choose _Build_ to build a specific target.
|
|||||||
|
|
||||||
For example, build the `material_sandbox` sample and run it from the `out` directory with:
|
For example, build the `material_sandbox` sample and run it from the `out` directory with:
|
||||||
|
|
||||||
```bat
|
```
|
||||||
samples\Debug\material_sandbox.exe ..\assets\models\monkey\monkey.obj
|
> samples\Debug\material_sandbox.exe ..\assets\models\monkey\monkey.obj
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use CMake to invoke the build without opening Visual Studio. For example, from the
|
You can also use CMake to invoke the build without opening Visual Studio. For example, from the
|
||||||
`out` folder run the following command.
|
`out` folder run the following command.
|
||||||
|
|
||||||
```bat
|
```
|
||||||
cmake --build . --target gltf_viewer --config Release
|
> cmake --build . --target gltf_viewer --config Release
|
||||||
```
|
```
|
||||||
|
|
||||||
### Android
|
### Android
|
||||||
@@ -237,8 +237,8 @@ To build Android on Windows machines, see [android/Windows.md](android/Windows.m
|
|||||||
The easiest way to build Filament for Android is to use `build.sh` and the
|
The easiest way to build Filament for Android is to use `build.sh` and the
|
||||||
`-p android` flag. For instance to build the release target:
|
`-p android` flag. For instance to build the release target:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh -p android release
|
$ ./build.sh -p android release
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `build.sh -h` for more information.
|
Run `build.sh -h` for more information.
|
||||||
@@ -248,23 +248,23 @@ Run `build.sh -h` for more information.
|
|||||||
Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
|
Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
|
||||||
below show how to build Filament for ARM 64-bit (`aarch64`).
|
below show how to build Filament for ARM 64-bit (`aarch64`).
|
||||||
|
|
||||||
```shell
|
```
|
||||||
mkdir out/android-build-release-aarch64
|
$ mkdir out/android-build-release-aarch64
|
||||||
cd out/android-build-release-aarch64
|
$ cd out/android-build-release-aarch64
|
||||||
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-aarch64-linux-android.cmake \
|
$ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-aarch64-linux-android.cmake \
|
||||||
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../android-release/filament ../..
|
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../android-release/filament ../..
|
||||||
```
|
```
|
||||||
|
|
||||||
And then invoke `ninja`:
|
And then invoke `ninja`:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
ninja install
|
$ ninja install
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
```shell
|
```
|
||||||
ninja install/strip
|
$ ninja install/strip
|
||||||
```
|
```
|
||||||
|
|
||||||
This will generate Filament's Android binaries in `out/android-release`. This location is important
|
This will generate Filament's Android binaries in `out/android-release`. This location is important
|
||||||
@@ -296,8 +296,8 @@ AAR.
|
|||||||
Alternatively you can build the AAR from the command line by executing the following in the
|
Alternatively you can build the AAR from the command line by executing the following in the
|
||||||
`android/` directory:
|
`android/` directory:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./gradlew -Pcom.google.android.filament.dist-dir=../../out/android-release/filament assembleRelease
|
$ ./gradlew -Pcom.google.android.filament.dist-dir=../../out/android-release/filament assembleRelease
|
||||||
```
|
```
|
||||||
|
|
||||||
The `-Pcom.google.android.filament.dist-dir` can be used to specify a different installation
|
The `-Pcom.google.android.filament.dist-dir` can be used to specify a different installation
|
||||||
@@ -311,7 +311,7 @@ sure to add the newly created module as a dependency to your application.
|
|||||||
If you do not wish to include all supported ABIs, make sure to create the appropriate flavors in
|
If you do not wish to include all supported ABIs, make sure to create the appropriate flavors in
|
||||||
your Gradle build file. For example:
|
your Gradle build file. For example:
|
||||||
|
|
||||||
```gradle
|
```
|
||||||
flavorDimensions 'cpuArch'
|
flavorDimensions 'cpuArch'
|
||||||
productFlavors {
|
productFlavors {
|
||||||
arm8 {
|
arm8 {
|
||||||
@@ -353,7 +353,7 @@ started, follow the instructions for building Filament on your platform ([macOS]
|
|||||||
Next, you need to install the Emscripten SDK. The following instructions show how to install the
|
Next, you need to install the Emscripten SDK. The following instructions show how to install the
|
||||||
same version that our continuous builds use.
|
same version that our continuous builds use.
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cd <your chosen parent folder for the emscripten SDK>
|
cd <your chosen parent folder for the emscripten SDK>
|
||||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.15.zip > emsdk.zip
|
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.15.zip > emsdk.zip
|
||||||
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
||||||
@@ -364,7 +364,7 @@ source ./emsdk_env.sh
|
|||||||
|
|
||||||
After this you can invoke the [easy build](#easy-build) script as follows:
|
After this you can invoke the [easy build](#easy-build) script as follows:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
export EMSDK=<your chosen home for the emscripten SDK>
|
export EMSDK=<your chosen home for the emscripten SDK>
|
||||||
./build.sh -p webgl release
|
./build.sh -p webgl release
|
||||||
```
|
```
|
||||||
@@ -374,7 +374,7 @@ creates a `samples` folder that can be used as the root of a simple static web s
|
|||||||
cannot open the HTML directly from the filesystem due to CORS. We recommend using the emrun tool
|
cannot open the HTML directly from the filesystem due to CORS. We recommend using the emrun tool
|
||||||
to create a quick localhost server:
|
to create a quick localhost server:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
emrun out/cmake-webgl-release/web/samples --no_browser --port 8000
|
emrun out/cmake-webgl-release/web/samples --no_browser --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ Some of the samples accept FBX/OBJ meshes while others rely on the `filamesh` fi
|
|||||||
generate a `filamesh ` file from an FBX/OBJ asset, run the `filamesh` tool
|
generate a `filamesh ` file from an FBX/OBJ asset, run the `filamesh` tool
|
||||||
(`./tools/filamesh/filamesh` in your build directory):
|
(`./tools/filamesh/filamesh` in your build directory):
|
||||||
|
|
||||||
```shell
|
```
|
||||||
filamesh ./assets/models/monkey/monkey.obj monkey.filamesh
|
filamesh ./assets/models/monkey/monkey.obj monkey.filamesh
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ files for the IBL (which are PNGs containing `R11F_G11F_B10F` data) or a path to
|
|||||||
containing two `.ktx` files (one for the IBL itself, one for the skybox). To generate an IBL
|
containing two `.ktx` files (one for the IBL itself, one for the skybox). To generate an IBL
|
||||||
simply use this command:
|
simply use this command:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cmgen -f ktx -x ./ibls/ my_ibl.exr
|
cmgen -f ktx -x ./ibls/ my_ibl.exr
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -427,9 +427,9 @@ value is the desired roughness between 0 and 1.
|
|||||||
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
||||||
following commands:
|
following commands:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cd filament/filament
|
$ cd filament/filament
|
||||||
doxygen docs/doxygen/filament.doxygen
|
$ doxygen docs/doxygen/filament.doxygen
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally simply open `docs/html/index.html` in your web browser.
|
Finally simply open `docs/html/index.html` in your web browser.
|
||||||
@@ -439,7 +439,7 @@ Finally simply open `docs/html/index.html` in your web browser.
|
|||||||
To try out Filament's Vulkan support with SwiftShader, first build SwiftShader and set the
|
To try out Filament's Vulkan support with SwiftShader, first build SwiftShader and set the
|
||||||
`SWIFTSHADER_LD_LIBRARY_PATH` variable to the folder that contains `libvk_swiftshader.dylib`:
|
`SWIFTSHADER_LD_LIBRARY_PATH` variable to the folder that contains `libvk_swiftshader.dylib`:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
git clone https://github.com/google/swiftshader.git
|
git clone https://github.com/google/swiftshader.git
|
||||||
cd swiftshader/build
|
cd swiftshader/build
|
||||||
cmake .. && make -j
|
cmake .. && make -j
|
||||||
@@ -454,7 +454,7 @@ Continuous testing turnaround can be quite slow if you need to build SwiftShader
|
|||||||
provide an Ubuntu-based Docker image that has it already built. The Docker image also includes
|
provide an Ubuntu-based Docker image that has it already built. The Docker image also includes
|
||||||
everything necessary for building Filament. You can fetch and run the image as follows:
|
everything necessary for building Filament. You can fetch and run the image as follows:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
docker pull ghcr.io/filament-assets/swiftshader
|
docker pull ghcr.io/filament-assets/swiftshader
|
||||||
docker run -it ghcr.io/filament-assets/swiftshader
|
docker run -it ghcr.io/filament-assets/swiftshader
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -3,14 +3,6 @@
|
|||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
cmake_minimum_required(VERSION 3.19)
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
# ==================================================================================================
|
|
||||||
# Toolchain configuration
|
|
||||||
# ==================================================================================================
|
|
||||||
if (APPLE AND NOT IOS)
|
|
||||||
# This must be set before project() is called
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Project declaration
|
# Project declaration
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ again.
|
|||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
See [CODE_STYLE.md](/CODE_STYLE.md)
|
See [CodeStyle.md](/CODE_STYLE.md)
|
||||||
|
|
||||||
## Code reviews
|
## Code reviews
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,9 @@ 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
|
||||||
|
|
||||||
|
- Fix possible NPE when updating fog options from Java/Kotlin
|
||||||
|
- The `emissive` property was not applied properly to `MASKED` materials, and could cause
|
||||||
|
dark fringes to appear (recompile materials)
|
||||||
|
- Allow glTF materials with transmission/volume extensions to choose their alpha mode
|
||||||
|
instead of forcing `MASKED`
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.43.0'
|
implementation 'com.google.android.filament:filament-android:1.42.0'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@ 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
|
```
|
||||||
pod 'Filament', '~> 1.43.0'
|
pod 'Filament', '~> 1.42.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Snapshots
|
### Snapshots
|
||||||
|
|||||||
@@ -7,28 +7,8 @@ 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.43.0
|
|
||||||
|
|
||||||
- gltfio: Fix possible change of scale sign when decomposing transform matrix for animation
|
|
||||||
- engine: Fixes "stable" shadows (see b/299310624)
|
|
||||||
|
|
||||||
## v1.42.2
|
|
||||||
|
|
||||||
- Fix possible NPE when updating fog options from Java/Kotlin
|
|
||||||
- The `emissive` property was not applied properly to `MASKED` materials, and could cause
|
|
||||||
dark fringes to appear (recompile materials)
|
|
||||||
- Allow glTF materials with transmission/volume extensions to choose their alpha mode
|
|
||||||
instead of forcing `MASKED`
|
|
||||||
- Fix a crash in gltfio when not using ubershaders
|
|
||||||
- Use flatmat for mat parameter in jsbinding
|
|
||||||
- Fix TextureFlags for sheenRoughnessMap when textures of sheenRoughnessMap and sheenColorMap is same
|
|
||||||
- Directional shadows can now be transformed (b/297095805)
|
|
||||||
|
|
||||||
## v1.42.1
|
## v1.42.1
|
||||||
|
|
||||||
- Fix potential `EXC_BAD_ACCESS` with Metal backend: b/297059776
|
|
||||||
- `setFrameCompletedCallback` now takes a `backend::CallbackHandler`.
|
|
||||||
|
|
||||||
## v1.42.0
|
## v1.42.0
|
||||||
|
|
||||||
- engine: add preliminary support for instanced stereoscopic rendering [⚠️ **Recompile materials**]
|
- engine: add preliminary support for instanced stereoscopic rendering [⚠️ **Recompile materials**]
|
||||||
|
|||||||
@@ -79,8 +79,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
|||||||
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
|
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
|
||||||
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
|
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
|
||||||
jboolean screenSpaceContactShadows, jint stepCount,
|
jboolean screenSpaceContactShadows, jint stepCount,
|
||||||
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius,
|
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
|
||||||
jfloatArray transform) {
|
|
||||||
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
|
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
|
||||||
LightManager::ShadowOptions shadowOptions {
|
LightManager::ShadowOptions shadowOptions {
|
||||||
.mapSize = (uint32_t)mapSize,
|
.mapSize = (uint32_t)mapSize,
|
||||||
@@ -103,18 +102,12 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
|||||||
},
|
},
|
||||||
.shadowBulbRadius = shadowBulbRadius
|
.shadowBulbRadius = shadowBulbRadius
|
||||||
};
|
};
|
||||||
|
|
||||||
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
|
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
|
||||||
const jsize splitCount = std::min((jsize) 3, env->GetArrayLength(splitPositions));
|
const jsize splitCount = std::min((jsize) 3, env->GetArrayLength(splitPositions));
|
||||||
std::copy_n(nativeSplits, splitCount, shadowOptions.cascadeSplitPositions);
|
for (jsize i = 0; i < splitCount; i++) {
|
||||||
|
shadowOptions.cascadeSplitPositions[i] = nativeSplits[i];
|
||||||
|
}
|
||||||
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
|
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
|
||||||
|
|
||||||
jfloat* nativeTransform = env->GetFloatArrayElements(transform, NULL);
|
|
||||||
std::copy_n(nativeTransform,
|
|
||||||
std::min(4, env->GetArrayLength(transform)),
|
|
||||||
shadowOptions.transform.xyzw.v);
|
|
||||||
env->ReleaseFloatArrayElements(transform, nativeTransform, 0);
|
|
||||||
|
|
||||||
builder->shadowOptions(shadowOptions);
|
builder->shadowOptions(shadowOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-14
@@ -258,7 +258,6 @@ public class LightManager {
|
|||||||
* shadows that are too far and wouldn't contribute to the scene much, improving
|
* shadows that are too far and wouldn't contribute to the scene much, improving
|
||||||
* performance and quality. This value is always positive.
|
* performance and quality. This value is always positive.
|
||||||
* Use 0.0f to use the camera far distance.
|
* Use 0.0f to use the camera far distance.
|
||||||
* This only affect directional lights.
|
|
||||||
*/
|
*/
|
||||||
public float shadowFar = 0.0f;
|
public float shadowFar = 0.0f;
|
||||||
|
|
||||||
@@ -369,17 +368,6 @@ public class LightManager {
|
|||||||
* enabled. (2cm by default).
|
* enabled. (2cm by default).
|
||||||
*/
|
*/
|
||||||
public float shadowBulbRadius = 0.02f;
|
public float shadowBulbRadius = 0.02f;
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the shadow direction. Must be a unit quaternion.
|
|
||||||
* The default is identity.
|
|
||||||
* Ignored if the light type isn't directional. For artistic use. Use with caution.
|
|
||||||
* The quaternion is stored as the imaginary part in the first 3 elements and the real
|
|
||||||
* part in the last element of the transform array.
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
@Size(min = 4, max = 4)
|
|
||||||
public float[] transform = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ShadowCascades {
|
public static class ShadowCascades {
|
||||||
@@ -518,7 +506,7 @@ public class LightManager {
|
|||||||
options.polygonOffsetConstant, options.polygonOffsetSlope,
|
options.polygonOffsetConstant, options.polygonOffsetSlope,
|
||||||
options.screenSpaceContactShadows,
|
options.screenSpaceContactShadows,
|
||||||
options.stepCount, options.maxShadowDistance,
|
options.stepCount, options.maxShadowDistance,
|
||||||
options.elvsm, options.blurWidth, options.shadowBulbRadius, options.transform);
|
options.elvsm, options.blurWidth, options.shadowBulbRadius);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1181,7 +1169,7 @@ public class LightManager {
|
|||||||
boolean stable, boolean lispsm,
|
boolean stable, boolean lispsm,
|
||||||
float polygonOffsetConstant, float polygonOffsetSlope,
|
float polygonOffsetConstant, float polygonOffsetSlope,
|
||||||
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
|
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
|
||||||
boolean elvsm, float blurWidth, float shadowBulbRadius, float[] transform);
|
boolean elvsm, float blurWidth, float shadowBulbRadius);
|
||||||
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
|
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
|
||||||
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
|
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
|
||||||
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
|
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ set(GLTFIO_SRCS
|
|||||||
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
|
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
|
||||||
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
|
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
|
||||||
${GLTFIO_DIR}/include/gltfio/NodeManager.h
|
${GLTFIO_DIR}/include/gltfio/NodeManager.h
|
||||||
${GLTFIO_DIR}/include/gltfio/TrsTransformManager.h
|
|
||||||
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
|
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
|
||||||
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
|
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
|
||||||
${GLTFIO_DIR}/include/gltfio/math.h
|
${GLTFIO_DIR}/include/gltfio/math.h
|
||||||
@@ -70,12 +69,10 @@ set(GLTFIO_SRCS
|
|||||||
${GLTFIO_DIR}/src/FilamentAsset.cpp
|
${GLTFIO_DIR}/src/FilamentAsset.cpp
|
||||||
${GLTFIO_DIR}/src/FilamentInstance.cpp
|
${GLTFIO_DIR}/src/FilamentInstance.cpp
|
||||||
${GLTFIO_DIR}/src/FNodeManager.h
|
${GLTFIO_DIR}/src/FNodeManager.h
|
||||||
${GLTFIO_DIR}/src/FTrsTransformManager.h
|
|
||||||
${GLTFIO_DIR}/src/GltfEnums.h
|
${GLTFIO_DIR}/src/GltfEnums.h
|
||||||
${GLTFIO_DIR}/src/Ktx2Provider.cpp
|
${GLTFIO_DIR}/src/Ktx2Provider.cpp
|
||||||
${GLTFIO_DIR}/src/MaterialProvider.cpp
|
${GLTFIO_DIR}/src/MaterialProvider.cpp
|
||||||
${GLTFIO_DIR}/src/NodeManager.cpp
|
${GLTFIO_DIR}/src/NodeManager.cpp
|
||||||
${GLTFIO_DIR}/src/TrsTransformManager.cpp
|
|
||||||
${GLTFIO_DIR}/src/ResourceLoader.cpp
|
${GLTFIO_DIR}/src/ResourceLoader.cpp
|
||||||
${GLTFIO_DIR}/src/StbProvider.cpp
|
${GLTFIO_DIR}/src/StbProvider.cpp
|
||||||
${GLTFIO_DIR}/src/TangentsJob.cpp
|
${GLTFIO_DIR}/src/TangentsJob.cpp
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.43.0
|
VERSION_NAME=1.42.0
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ compile Filament's native library and Filament's AAR for this project. The easie
|
|||||||
is to install all the required dependencies and to run the following commands at the root of the
|
is to install all the required dependencies and to run the following commands at the root of the
|
||||||
source tree:
|
source tree:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
./build.sh -p desktop -i release
|
$ ./build.sh -p desktop -i release
|
||||||
./build.sh -p android release
|
$ ./build.sh -p android release
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build all the native components and the AAR required by this sample application.
|
This will build all the native components and the AAR required by this sample application.
|
||||||
@@ -100,8 +100,8 @@ distribution/install directory for desktop (produced by make/ninja install). Thi
|
|||||||
contain `bin/matc` and `bin/cmgen`.
|
contain `bin/matc` and `bin/cmgen`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```shell
|
```
|
||||||
./gradlew -Pfilament_tools_dir=../../dist-release assembleDebug
|
$ ./gradlew -Pfilament_tools_dir=../../dist-release assembleDebug
|
||||||
```
|
```
|
||||||
|
|
||||||
## Important: SDK location
|
## Important: SDK location
|
||||||
@@ -110,24 +110,14 @@ Either ensure your `ANDROID_HOME` environment variable is set or make sure the r
|
|||||||
contains a `local.properties` file with the `sdk.dir` property pointing to your installation of
|
contains a `local.properties` file with the `sdk.dir` property pointing to your installation of
|
||||||
the Android SDK.
|
the Android SDK.
|
||||||
|
|
||||||
## Compiling
|
## Android Studio
|
||||||
|
|
||||||
### Android Studio
|
|
||||||
|
|
||||||
You must use the latest stable release of Android Studio. To open the project, point Studio to the
|
You must use the latest stable release of Android Studio. To open the project, point Studio to the
|
||||||
`android` folder. After opening the project and syncing to gradle, select the sample of your choice
|
`android` folder. After opening the project and syncing to gradle, select the sample of your choice
|
||||||
using the drop-down widget in the toolbar.
|
using the drop-down widget in the toolbar.
|
||||||
|
|
||||||
|
## Compiling
|
||||||
|
|
||||||
To compile and run each sample make sure you have selected the appropriate build variant
|
To compile and run each sample make sure you have selected the appropriate build variant
|
||||||
(arm7, arm8, x86 or x86_64). If you are not sure you can simply select the "universal"
|
(arm7, arm8, x86 or x86_64). If you are not sure you can simply select the "universal"
|
||||||
variant which includes all the other ones.
|
variant which includes all the other ones.
|
||||||
|
|
||||||
### Command Line
|
|
||||||
|
|
||||||
From the `android` directory in the project root:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./gradlew :samples:sample-hello-triangle:installDebug
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `sample-hello-triangle` with your preferred project.
|
|
||||||
|
|||||||
@@ -210,10 +210,13 @@ function build_desktop_target {
|
|||||||
echo "Building ${lc_target} in out/cmake-${lc_target}..."
|
echo "Building ${lc_target} in out/cmake-${lc_target}..."
|
||||||
mkdir -p "out/cmake-${lc_target}"
|
mkdir -p "out/cmake-${lc_target}"
|
||||||
|
|
||||||
pushd "out/cmake-${lc_target}" > /dev/null
|
cd "out/cmake-${lc_target}"
|
||||||
|
|
||||||
|
# On macOS, set the deployment target to 10.15.
|
||||||
local lc_name=$(echo "${UNAME}" | tr '[:upper:]' '[:lower:]')
|
local lc_name=$(echo "${UNAME}" | tr '[:upper:]' '[:lower:]')
|
||||||
if [[ "${lc_name}" == "darwin" ]]; then
|
if [[ "${lc_name}" == "darwin" ]]; then
|
||||||
|
local deployment_target="-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15"
|
||||||
|
|
||||||
if [[ "${BUILD_UNIVERSAL_LIBRARIES}" == "true" ]]; then
|
if [[ "${BUILD_UNIVERSAL_LIBRARIES}" == "true" ]]; then
|
||||||
local architectures="-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64"
|
local architectures="-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64"
|
||||||
fi
|
fi
|
||||||
@@ -230,6 +233,7 @@ function build_desktop_target {
|
|||||||
${MATDBG_OPTION} \
|
${MATDBG_OPTION} \
|
||||||
${MATOPT_OPTION} \
|
${MATOPT_OPTION} \
|
||||||
${ASAN_UBSAN_OPTION} \
|
${ASAN_UBSAN_OPTION} \
|
||||||
|
${deployment_target} \
|
||||||
${architectures} \
|
${architectures} \
|
||||||
../..
|
../..
|
||||||
fi
|
fi
|
||||||
@@ -243,13 +247,12 @@ function build_desktop_target {
|
|||||||
if [[ -d "../${lc_target}/filament" ]]; then
|
if [[ -d "../${lc_target}/filament" ]]; then
|
||||||
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
||||||
echo "Generating out/filament-${lc_target}-${LC_UNAME}.tgz..."
|
echo "Generating out/filament-${lc_target}-${LC_UNAME}.tgz..."
|
||||||
pushd "../${lc_target}" > /dev/null
|
cd "../${lc_target}"
|
||||||
tar -czvf "../filament-${lc_target}-${LC_UNAME}.tgz" filament
|
tar -czvf "../filament-${lc_target}-${LC_UNAME}.tgz" filament
|
||||||
popd > /dev/null
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_desktop {
|
function build_desktop {
|
||||||
@@ -267,7 +270,7 @@ function build_webgl_with_target {
|
|||||||
|
|
||||||
echo "Building WebGL ${lc_target}..."
|
echo "Building WebGL ${lc_target}..."
|
||||||
mkdir -p "out/cmake-webgl-${lc_target}"
|
mkdir -p "out/cmake-webgl-${lc_target}"
|
||||||
pushd "out/cmake-webgl-${lc_target}" > /dev/null
|
cd "out/cmake-webgl-${lc_target}"
|
||||||
|
|
||||||
if [[ ! "${BUILD_TARGETS}" ]]; then
|
if [[ ! "${BUILD_TARGETS}" ]]; then
|
||||||
BUILD_TARGETS=${BUILD_CUSTOM_TARGETS}
|
BUILD_TARGETS=${BUILD_CUSTOM_TARGETS}
|
||||||
@@ -304,17 +307,17 @@ function build_webgl_with_target {
|
|||||||
|
|
||||||
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
||||||
echo "Generating out/filament-${lc_target}-web.tgz..."
|
echo "Generating out/filament-${lc_target}-web.tgz..."
|
||||||
pushd web/filament-js > /dev/null
|
cd web/filament-js
|
||||||
tar -cvf "../../../filament-${lc_target}-web.tar" filament.js
|
tar -cvf "../../../filament-${lc_target}-web.tar" filament.js
|
||||||
tar -rvf "../../../filament-${lc_target}-web.tar" filament.wasm
|
tar -rvf "../../../filament-${lc_target}-web.tar" filament.wasm
|
||||||
tar -rvf "../../../filament-${lc_target}-web.tar" filament.d.ts
|
tar -rvf "../../../filament-${lc_target}-web.tar" filament.d.ts
|
||||||
popd > /dev/null
|
cd -
|
||||||
gzip -c "../filament-${lc_target}-web.tar" > "../filament-${lc_target}-web.tgz"
|
gzip -c "../filament-${lc_target}-web.tar" > "../filament-${lc_target}-web.tgz"
|
||||||
rm "../filament-${lc_target}-web.tar"
|
rm "../filament-${lc_target}-web.tar"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_webgl {
|
function build_webgl {
|
||||||
@@ -345,7 +348,7 @@ function build_android_target {
|
|||||||
echo "Building Android ${lc_target} (${arch})..."
|
echo "Building Android ${lc_target} (${arch})..."
|
||||||
mkdir -p "out/cmake-android-${lc_target}-${arch}"
|
mkdir -p "out/cmake-android-${lc_target}-${arch}"
|
||||||
|
|
||||||
pushd "out/cmake-android-${lc_target}-${arch}" > /dev/null
|
cd "out/cmake-android-${lc_target}-${arch}"
|
||||||
|
|
||||||
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
||||||
cmake \
|
cmake \
|
||||||
@@ -364,7 +367,7 @@ function build_android_target {
|
|||||||
# We must always install Android libraries to build the AAR
|
# We must always install Android libraries to build the AAR
|
||||||
${BUILD_COMMAND} install
|
${BUILD_COMMAND} install
|
||||||
|
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_android_arch {
|
function build_android_arch {
|
||||||
@@ -385,9 +388,9 @@ function archive_android {
|
|||||||
if [[ -d "out/android-${lc_target}/filament" ]]; then
|
if [[ -d "out/android-${lc_target}/filament" ]]; then
|
||||||
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
||||||
echo "Generating out/filament-android-${lc_target}-${LC_UNAME}.tgz..."
|
echo "Generating out/filament-android-${lc_target}-${LC_UNAME}.tgz..."
|
||||||
pushd "out/android-${lc_target}" > /dev/null
|
cd "out/android-${lc_target}"
|
||||||
tar -czvf "../filament-android-${lc_target}-${LC_UNAME}.tgz" filament
|
tar -czvf "../filament-android-${lc_target}-${LC_UNAME}.tgz" filament
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -465,7 +468,7 @@ function build_android {
|
|||||||
archive_android "Release"
|
archive_android "Release"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pushd android > /dev/null
|
cd android
|
||||||
|
|
||||||
if [[ "${ISSUE_DEBUG_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_DEBUG_BUILD}" == "true" ]]; then
|
||||||
./gradlew \
|
./gradlew \
|
||||||
@@ -566,7 +569,7 @@ function build_android {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
popd > /dev/null
|
cd ..
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_ios_target {
|
function build_ios_target {
|
||||||
@@ -577,7 +580,7 @@ function build_ios_target {
|
|||||||
echo "Building iOS ${lc_target} (${arch}) for ${platform}..."
|
echo "Building iOS ${lc_target} (${arch}) for ${platform}..."
|
||||||
mkdir -p "out/cmake-ios-${lc_target}-${arch}"
|
mkdir -p "out/cmake-ios-${lc_target}-${arch}"
|
||||||
|
|
||||||
pushd "out/cmake-ios-${lc_target}-${arch}" > /dev/null
|
cd "out/cmake-ios-${lc_target}-${arch}"
|
||||||
|
|
||||||
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
||||||
cmake \
|
cmake \
|
||||||
@@ -601,7 +604,7 @@ function build_ios_target {
|
|||||||
${BUILD_COMMAND} ${INSTALL_COMMAND}
|
${BUILD_COMMAND} ${INSTALL_COMMAND}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
function archive_ios {
|
function archive_ios {
|
||||||
@@ -610,9 +613,9 @@ function archive_ios {
|
|||||||
if [[ -d "out/ios-${lc_target}/filament" ]]; then
|
if [[ -d "out/ios-${lc_target}/filament" ]]; then
|
||||||
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
|
||||||
echo "Generating out/filament-${lc_target}-ios.tgz..."
|
echo "Generating out/filament-${lc_target}-ios.tgz..."
|
||||||
pushd "out/ios-${lc_target}" > /dev/null
|
cd "out/ios-${lc_target}"
|
||||||
tar -czvf "../filament-${lc_target}-ios.tgz" filament
|
tar -czvf "../filament-${lc_target}-ios.tgz" filament
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -671,14 +674,14 @@ function build_web_docs {
|
|||||||
|
|
||||||
mkdir -p out/web-docs
|
mkdir -p out/web-docs
|
||||||
cp -f docs/web-docs-package.json out/web-docs/package.json
|
cp -f docs/web-docs-package.json out/web-docs/package.json
|
||||||
pushd out/web-docs > /dev/null
|
cd out/web-docs
|
||||||
|
|
||||||
npm install > /dev/null
|
npm install > /dev/null
|
||||||
|
|
||||||
# Generate documents
|
# Generate documents
|
||||||
npx markdeep-rasterizer ../../docs/Filament.md.html ../../docs/Materials.md.html ../../docs/
|
npx markdeep-rasterizer ../../docs/Filament.md.html ../../docs/Materials.md.html ../../docs/
|
||||||
|
|
||||||
popd > /dev/null
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate_build_command {
|
function validate_build_command {
|
||||||
@@ -751,16 +754,6 @@ function run_tests {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_debug_release_build {
|
|
||||||
if [[ "${ISSUE_DEBUG_BUILD}" == "true" || "${ISSUE_RELEASE_BUILD}" == "true" ]]; then
|
|
||||||
"$@";
|
|
||||||
else
|
|
||||||
echo "You must declare a debug or release target for $@ builds."
|
|
||||||
echo ""
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Beginning of the script
|
# Beginning of the script
|
||||||
|
|
||||||
pushd "$(dirname "$0")" > /dev/null
|
pushd "$(dirname "$0")" > /dev/null
|
||||||
@@ -769,7 +762,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
case ${opt} in
|
case ${opt} in
|
||||||
h)
|
h)
|
||||||
print_help
|
print_help
|
||||||
exit 0
|
exit 1
|
||||||
;;
|
;;
|
||||||
a)
|
a)
|
||||||
ISSUE_ARCHIVES=true
|
ISSUE_ARCHIVES=true
|
||||||
@@ -805,7 +798,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
platforms=$(echo "${OPTARG}" | tr ',' '\n')
|
platforms=$(echo "${OPTARG}" | tr ',' '\n')
|
||||||
for platform in ${platforms}
|
for platform in ${platforms}
|
||||||
do
|
do
|
||||||
case $(echo "${platform}" | tr '[:upper:]' '[:lower:]') in
|
case ${platform} in
|
||||||
desktop)
|
desktop)
|
||||||
ISSUE_DESKTOP_BUILD=true
|
ISSUE_DESKTOP_BUILD=true
|
||||||
;;
|
;;
|
||||||
@@ -824,12 +817,6 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
ISSUE_DESKTOP_BUILD=true
|
ISSUE_DESKTOP_BUILD=true
|
||||||
ISSUE_WEBGL_BUILD=false
|
ISSUE_WEBGL_BUILD=false
|
||||||
;;
|
;;
|
||||||
*)
|
|
||||||
echo "Unknown platform ${platform}"
|
|
||||||
echo "Platform must be one of [desktop|android|ios|webgl|all]"
|
|
||||||
echo ""
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
@@ -842,7 +829,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
abis=$(echo "${OPTARG}" | tr ',' '\n')
|
abis=$(echo "${OPTARG}" | tr ',' '\n')
|
||||||
for abi in ${abis}
|
for abi in ${abis}
|
||||||
do
|
do
|
||||||
case $(echo "${abi}" | tr '[:upper:]' '[:lower:]') in
|
case ${abi} in
|
||||||
armeabi-v7a)
|
armeabi-v7a)
|
||||||
ABI_ARMEABI_V7A=true
|
ABI_ARMEABI_V7A=true
|
||||||
;;
|
;;
|
||||||
@@ -861,12 +848,6 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
ABI_X86=true
|
ABI_X86=true
|
||||||
ABI_X86_64=true
|
ABI_X86_64=true
|
||||||
;;
|
;;
|
||||||
*)
|
|
||||||
echo "Unknown abi ${abi}"
|
|
||||||
echo "ABI must be one of [armeabi-v7a|arm64-v8a|x86|x86_64|all]"
|
|
||||||
echo ""
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
@@ -930,9 +911,9 @@ fi
|
|||||||
shift $((OPTIND - 1))
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
for arg; do
|
for arg; do
|
||||||
if [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "release" ]]; then
|
if [[ "${arg}" == "release" ]]; then
|
||||||
ISSUE_RELEASE_BUILD=true
|
ISSUE_RELEASE_BUILD=true
|
||||||
elif [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "debug" ]]; then
|
elif [[ "${arg}" == "debug" ]]; then
|
||||||
ISSUE_DEBUG_BUILD=true
|
ISSUE_DEBUG_BUILD=true
|
||||||
else
|
else
|
||||||
BUILD_CUSTOM_TARGETS="${BUILD_CUSTOM_TARGETS} ${arg}"
|
BUILD_CUSTOM_TARGETS="${BUILD_CUSTOM_TARGETS} ${arg}"
|
||||||
@@ -950,19 +931,19 @@ if [[ "${ISSUE_CLEAN_AGGRESSIVE}" == "true" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_DESKTOP_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_DESKTOP_BUILD}" == "true" ]]; then
|
||||||
check_debug_release_build build_desktop
|
build_desktop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_ANDROID_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_ANDROID_BUILD}" == "true" ]]; then
|
||||||
check_debug_release_build build_android
|
build_android
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_IOS_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_IOS_BUILD}" == "true" ]]; then
|
||||||
check_debug_release_build build_ios
|
build_ios
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_WEBGL_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_WEBGL_BUILD}" == "true" ]]; then
|
||||||
check_debug_release_build build_webgl
|
build_webgl
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_WEB_DOCS}" == "true" ]]; then
|
if [[ "${ISSUE_WEB_DOCS}" == "true" ]]; then
|
||||||
|
|||||||
+7
-7
@@ -61,7 +61,7 @@ with the platform name, for example, `filament-20181009-linux.tgz`.
|
|||||||
|
|
||||||
Create a file, `main.cpp`, in the same directory with the following contents:
|
Create a file, `main.cpp`, in the same directory with the following contents:
|
||||||
|
|
||||||
```c++
|
```
|
||||||
#include <filament/FilamentAPI.h>
|
#include <filament/FilamentAPI.h>
|
||||||
#include <filament/Engine.h>
|
#include <filament/Engine.h>
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ Copy your platform's Makefile below into a `Makefile` inside the same directory.
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
|
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
|
||||||
CC=clang++
|
CC=clang++
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ clean:
|
|||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
|
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
|
||||||
FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo
|
FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo
|
||||||
CC=clang++
|
CC=clang++
|
||||||
@@ -137,7 +137,7 @@ be sure to also include `matdbg.lib` in `FILAMENT_LIBS`.
|
|||||||
When building Filament from source, the `USE_STATIC_CRT` CMake option can be
|
When building Filament from source, the `USE_STATIC_CRT` CMake option can be
|
||||||
used to change the run-time library version.
|
used to change the run-time library version.
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \
|
FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \
|
||||||
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib
|
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib
|
||||||
CC=cl.exe
|
CC=cl.exe
|
||||||
@@ -174,9 +174,9 @@ and invoke `nmake` instead of `make`.
|
|||||||
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
||||||
following commands:
|
following commands:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cd filament/filament
|
$ cd filament/filament
|
||||||
doxygen docs/doxygen/filament.doxygen
|
$ doxygen docs/doxygen/filament.doxygen
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally simply open `docs/html/index.html` in your web browser.
|
Finally simply open `docs/html/index.html` in your web browser.
|
||||||
|
|||||||
@@ -412,7 +412,6 @@ if (APPLE)
|
|||||||
test/test_RenderExternalImage.cpp
|
test/test_RenderExternalImage.cpp
|
||||||
test/test_StencilBuffer.cpp
|
test/test_StencilBuffer.cpp
|
||||||
test/test_Scissor.cpp
|
test/test_Scissor.cpp
|
||||||
test/test_MipLevels.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(backend_test PRIVATE
|
target_link_libraries(backend_test PRIVATE
|
||||||
|
|||||||
@@ -813,22 +813,22 @@ struct SamplerParams { // NOLINT
|
|||||||
struct Hasher {
|
struct Hasher {
|
||||||
size_t operator()(SamplerParams p) const noexcept {
|
size_t operator()(SamplerParams p) const noexcept {
|
||||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
// we don't use std::hash<> here, so we don't have to include <functional>
|
||||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
return *reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&p));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EqualTo {
|
struct EqualTo {
|
||||||
bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept {
|
bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept {
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
auto* pLhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
auto* pRhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||||
return *pLhs == *pRhs;
|
return *pLhs == *pRhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LessThan {
|
struct LessThan {
|
||||||
bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept {
|
bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept {
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
auto* pLhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
auto* pRhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||||
return *pLhs == *pRhs;
|
return *pLhs == *pRhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -838,7 +838,6 @@ private:
|
|||||||
return SamplerParams::LessThan{}(lhs, rhs);
|
return SamplerParams::LessThan{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SamplerParams) == 4);
|
|
||||||
|
|
||||||
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
||||||
// see android/.../TextureSampler.cpp
|
// see android/.../TextureSampler.cpp
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
Program& operator=(const Program& rhs) = delete;
|
Program& operator=(const Program& rhs) = delete;
|
||||||
|
|
||||||
Program(Program&& rhs) noexcept;
|
Program(Program&& rhs) noexcept;
|
||||||
Program& operator=(Program&& rhs) noexcept = delete;
|
Program& operator=(Program&& rhs) noexcept;
|
||||||
|
|
||||||
~Program() noexcept;
|
~Program() noexcept;
|
||||||
|
|
||||||
@@ -104,9 +104,8 @@ public:
|
|||||||
Sampler const* samplers, size_t count) noexcept;
|
Sampler const* samplers, size_t count) noexcept;
|
||||||
|
|
||||||
struct SpecializationConstant {
|
struct SpecializationConstant {
|
||||||
using Type = std::variant<int32_t, float, bool>;
|
|
||||||
uint32_t id; // id set in glsl
|
uint32_t id; // id set in glsl
|
||||||
Type value; // value and type
|
std::variant<int32_t, float, bool> value; // value and type
|
||||||
};
|
};
|
||||||
|
|
||||||
Program& specializationConstants(
|
Program& specializationConstants(
|
||||||
|
|||||||
@@ -73,14 +73,32 @@ public:
|
|||||||
// a cost here (writing and reading the stack at each iteration), in the end it's
|
// a cost here (writing and reading the stack at each iteration), in the end it's
|
||||||
// probably better to pay the cost at just one location.
|
// probably better to pay the cost at just one location.
|
||||||
intptr_t next;
|
intptr_t next;
|
||||||
|
driver.mCurrentExecutingCommand = this;
|
||||||
mExecute(driver, this, &next);
|
mExecute(driver, this, &next);
|
||||||
return reinterpret_cast<CommandBase*>(reinterpret_cast<intptr_t>(this) + next);
|
return reinterpret_cast<CommandBase*>(reinterpret_cast<intptr_t>(this) + next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void captureCallstack() noexcept {
|
||||||
|
auto c = utils::CallStack::unwind(4);
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < c.getFrameCount() && i < 16; i++) {
|
||||||
|
mCallstack[i] = c[i];
|
||||||
|
}
|
||||||
|
for (; i < 16; i++) {
|
||||||
|
mCallstack[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printCallstack() noexcept {
|
||||||
|
auto c = utils::CallStack(mCallstack);
|
||||||
|
utils::slog.d << c << utils::io::endl;
|
||||||
|
}
|
||||||
|
|
||||||
inline ~CommandBase() noexcept = default;
|
inline ~CommandBase() noexcept = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Execute mExecute;
|
Execute mExecute;
|
||||||
|
std::array<intptr_t, 16> mCallstack = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -218,6 +236,7 @@ public:
|
|||||||
using Cmd = COMMAND_TYPE(methodName); \
|
using Cmd = COMMAND_TYPE(methodName); \
|
||||||
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
|
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
|
||||||
new(p) Cmd(mDispatcher.methodName##_, APPLY(std::move, params)); \
|
new(p) Cmd(mDispatcher.methodName##_, APPLY(std::move, params)); \
|
||||||
|
((Cmd*)p)->captureCallstack(); \
|
||||||
DEBUG_COMMAND_END(methodName, false); \
|
DEBUG_COMMAND_END(methodName, false); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +256,7 @@ public:
|
|||||||
using Cmd = COMMAND_TYPE(methodName##R); \
|
using Cmd = COMMAND_TYPE(methodName##R); \
|
||||||
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
|
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
|
||||||
new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params)); \
|
new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params)); \
|
||||||
|
((Cmd*)p)->captureCallstack(); \
|
||||||
DEBUG_COMMAND_END(methodName, false); \
|
DEBUG_COMMAND_END(methodName, false); \
|
||||||
return result; \
|
return result; \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ template<typename T>
|
|||||||
class ConcreteDispatcher;
|
class ConcreteDispatcher;
|
||||||
class Dispatcher;
|
class Dispatcher;
|
||||||
class CommandStream;
|
class CommandStream;
|
||||||
|
class CommandBase;
|
||||||
|
|
||||||
class Driver {
|
class Driver {
|
||||||
public:
|
public:
|
||||||
@@ -83,6 +84,8 @@ public:
|
|||||||
virtual void debugCommandEnd(CommandStream* cmds,
|
virtual void debugCommandEnd(CommandStream* cmds,
|
||||||
bool synchronous, const char* methodName) noexcept = 0;
|
bool synchronous, const char* methodName) noexcept = 0;
|
||||||
|
|
||||||
|
CommandBase* mCurrentExecutingCommand = nullptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Asynchronous calls here only to provide a type to CommandStream. They must be non-virtual
|
* Asynchronous calls here only to provide a type to CommandStream. They must be non-virtual
|
||||||
* so that calling the concrete implementation won't go through a vtable.
|
* so that calling the concrete implementation won't go through a vtable.
|
||||||
|
|||||||
@@ -26,6 +26,17 @@ Program::Program() noexcept { // NOLINT(modernize-use-equals-default)
|
|||||||
|
|
||||||
Program::Program(Program&& rhs) noexcept = default;
|
Program::Program(Program&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
Program& Program::operator=(Program&& rhs) noexcept {
|
||||||
|
mUniformBlocks.operator=(rhs.mUniformBlocks);
|
||||||
|
mSamplerGroups.operator=(std::move(rhs.mSamplerGroups));
|
||||||
|
mShadersSource.operator=(std::move(rhs.mShadersSource));
|
||||||
|
mName.operator=(std::move(rhs.mName));
|
||||||
|
mLogger.operator=(std::move(rhs.mLogger));
|
||||||
|
mSpecializationConstants.operator=(std::move(rhs.mSpecializationConstants));
|
||||||
|
mBindingUniformInfo.operator=(std::move(rhs.mBindingUniformInfo));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Program::~Program() noexcept = default;
|
Program::~Program() noexcept = default;
|
||||||
|
|
||||||
Program& Program::priorityQueue(CompilerPriorityQueue priorityQueue) noexcept {
|
Program& Program::priorityQueue(CompilerPriorityQueue priorityQueue) noexcept {
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|||||||
auto colorTexture = handle_cast<MetalTexture>(buffer.handle);
|
auto colorTexture = handle_cast<MetalTexture>(buffer.handle);
|
||||||
ASSERT_PRECONDITION(colorTexture->getMtlTextureForWrite(),
|
ASSERT_PRECONDITION(colorTexture->getMtlTextureForWrite(),
|
||||||
"Color texture passed to render target has no texture allocation");
|
"Color texture passed to render target has no texture allocation");
|
||||||
colorTexture->extendLodRangeTo(buffer.level);
|
colorTexture->updateLodRange(buffer.level);
|
||||||
colorAttachments[i] = { colorTexture, color[i].level, color[i].layer };
|
colorAttachments[i] = { colorTexture, color[i].level, color[i].layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +356,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|||||||
auto depthTexture = handle_cast<MetalTexture>(depth.handle);
|
auto depthTexture = handle_cast<MetalTexture>(depth.handle);
|
||||||
ASSERT_PRECONDITION(depthTexture->getMtlTextureForWrite(),
|
ASSERT_PRECONDITION(depthTexture->getMtlTextureForWrite(),
|
||||||
"Depth texture passed to render target has no texture allocation.");
|
"Depth texture passed to render target has no texture allocation.");
|
||||||
depthTexture->extendLodRangeTo(depth.level);
|
depthTexture->updateLodRange(depth.level);
|
||||||
depthAttachment = { depthTexture, depth.level, depth.layer };
|
depthAttachment = { depthTexture, depth.level, depth.layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +367,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|||||||
auto stencilTexture = handle_cast<MetalTexture>(stencil.handle);
|
auto stencilTexture = handle_cast<MetalTexture>(stencil.handle);
|
||||||
ASSERT_PRECONDITION(stencilTexture->getMtlTextureForWrite(),
|
ASSERT_PRECONDITION(stencilTexture->getMtlTextureForWrite(),
|
||||||
"Stencil texture passed to render target has no texture allocation.");
|
"Stencil texture passed to render target has no texture allocation.");
|
||||||
stencilTexture->extendLodRangeTo(stencil.level);
|
stencilTexture->updateLodRange(stencil.level);
|
||||||
stencilAttachment = { stencilTexture, stencil.level, stencil.layer };
|
stencilAttachment = { stencilTexture, stencil.level, stencil.layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,8 +789,6 @@ void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t ind
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint32_t maxLevel) {
|
void MetalDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint32_t maxLevel) {
|
||||||
auto tex = handle_cast<MetalTexture>(th);
|
|
||||||
tex->setLodRange(minLevel, maxLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
||||||
@@ -902,13 +900,14 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
|
|||||||
// 2. LOD-clamped textures
|
// 2. LOD-clamped textures
|
||||||
//
|
//
|
||||||
// Both of these cases prevent us from knowing the final id<MTLTexture> that will be bound into
|
// Both of these cases prevent us from knowing the final id<MTLTexture> that will be bound into
|
||||||
// the argument buffer representing the sampler group. So, we wait until draw call time to bind
|
// the argument buffer representing the sampler group. So, we bind what we can now and wait
|
||||||
// textures (done in finalizeSamplerGroup).
|
// until draw call time to bind any special cases (done in finalizeSamplerGroup).
|
||||||
// The good news is that once a render pass has started, the texture bindings won't change.
|
// The good news is that once a render pass has started, the texture bindings won't change.
|
||||||
// A SamplerGroup is "finalized" when all of its textures have been set and is ready for use in
|
// A SamplerGroup is "finalized" when all of its textures have been set and is ready for use in
|
||||||
// a draw call.
|
// a draw call.
|
||||||
// finalizeSamplerGroup has one additional responsibility: to call useResources for all the
|
// Even if we do know all the final textures at this point, we still wait until draw call time
|
||||||
// textures, which is required by Metal.
|
// to call finalizeSamplerGroup, which has one additional responsibility: to call useResources
|
||||||
|
// for all the textures, which is required by Metal.
|
||||||
for (size_t s = 0; s < data.size / sizeof(SamplerDescriptor); s++) {
|
for (size_t s = 0; s < data.size / sizeof(SamplerDescriptor); s++) {
|
||||||
if (!samplers[s].t) {
|
if (!samplers[s].t) {
|
||||||
// Assign a default texture / sampler to empty slots.
|
// Assign a default texture / sampler to empty slots.
|
||||||
@@ -931,6 +930,27 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
|
|||||||
sb->setFinalizedSampler(s, sampler);
|
sb->setFinalizedSampler(s, sampler);
|
||||||
|
|
||||||
sb->setTextureHandle(s, samplers[s].t);
|
sb->setTextureHandle(s, samplers[s].t);
|
||||||
|
|
||||||
|
auto* t = handle_cast<MetalTexture>(samplers[s].t);
|
||||||
|
assert_invariant(t);
|
||||||
|
|
||||||
|
// If this texture is an external texture, we defer binding the texture until draw call time
|
||||||
|
// (in finalizeSamplerGroup).
|
||||||
|
if (t->target == SamplerType::SAMPLER_EXTERNAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t->allLodsValid()) {
|
||||||
|
// The texture doesn't have all of its LODs loaded, and this could change by the time we
|
||||||
|
// issue a draw call with this sampler group. So, we defer binding the texture until
|
||||||
|
// draw call time (in finalizeSamplerGroup).
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, we know we have a valid MTLTexture that's guaranteed not to change.
|
||||||
|
id<MTLTexture> mtlTexture = t->getMtlTextureForRead();
|
||||||
|
assert_invariant(mtlTexture);
|
||||||
|
sb->setFinalizedTexture(s, mtlTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleDestroy(std::move(data));
|
scheduleDestroy(std::move(data));
|
||||||
@@ -1356,8 +1376,8 @@ void MetalDriver::blit(TargetBufferFlags buffers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
||||||
// All the id<MTLSamplerState> objects have already been bound to the argument buffer.
|
// All of the id<MTLSamplerState> objects have already been bound to the argument buffer.
|
||||||
// Here we bind all the textures.
|
// Here we bind any textures that were unable to be bound in updateSamplerGroup.
|
||||||
|
|
||||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(mContext);
|
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(mContext);
|
||||||
|
|
||||||
|
|||||||
@@ -217,14 +217,21 @@ public:
|
|||||||
void generateMipmaps() noexcept;
|
void generateMipmaps() noexcept;
|
||||||
|
|
||||||
// A texture starts out with none of its mip levels (also referred to as LODs) available for
|
// A texture starts out with none of its mip levels (also referred to as LODs) available for
|
||||||
// reading. 4 actions update the range of LODs available:
|
// reading. 3 actions update the range of LODs available:
|
||||||
// - calling loadImage
|
// - calling loadImage
|
||||||
// - calling generateMipmaps
|
// - calling generateMipmaps
|
||||||
// - using the texture as a render target attachment
|
// - using the texture as a render target attachment
|
||||||
// - calling setMinMaxLevels
|
// The range of available mips can only increase, never decrease.
|
||||||
// A texture's available mips are consistent throughout a render pass.
|
// A texture's available mips are consistent throughout a render pass.
|
||||||
void setLodRange(uint32_t minLevel, uint32_t maxLevel);
|
void updateLodRange(uint32_t level);
|
||||||
void extendLodRangeTo(uint32_t level);
|
void updateLodRange(uint32_t minLevel, uint32_t maxLevel);
|
||||||
|
|
||||||
|
// Returns true if the texture has all of its mip levels accessible for reading.
|
||||||
|
// For any MetalTexture, once this is true, will always return true.
|
||||||
|
// The value returned will remain consistent for an entire render pass.
|
||||||
|
bool allLodsValid() const {
|
||||||
|
return minLod == 0 && maxLod == levels - 1;
|
||||||
|
}
|
||||||
|
|
||||||
static MTLPixelFormat decidePixelFormat(MetalContext* context, TextureFormat format);
|
static MTLPixelFormat decidePixelFormat(MetalContext* context, TextureFormat format);
|
||||||
|
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
|
|||||||
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context),
|
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context),
|
||||||
externalImage(context) {
|
externalImage(context) {
|
||||||
texture = metalTexture;
|
texture = metalTexture;
|
||||||
setLodRange(0, levels - 1);
|
updateLodRange(0, levels - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalTexture::~MetalTexture() {
|
MetalTexture::~MetalTexture() {
|
||||||
@@ -658,14 +658,14 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extendLodRangeTo(level);
|
updateLodRange(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalTexture::generateMipmaps() noexcept {
|
void MetalTexture::generateMipmaps() noexcept {
|
||||||
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(&context) blitCommandEncoder];
|
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(&context) blitCommandEncoder];
|
||||||
[blitEncoder generateMipmapsForTexture:texture];
|
[blitEncoder generateMipmapsForTexture:texture];
|
||||||
[blitEncoder endEncoding];
|
[blitEncoder endEncoding];
|
||||||
setLodRange(0, texture.mipmapLevelCount - 1);
|
updateLodRange(0, texture.mipmapLevelCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalTexture::loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
void MetalTexture::loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
||||||
@@ -788,18 +788,18 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region
|
|||||||
context.blitter->blit(getPendingCommandBuffer(&context), args, "Texture upload blit");
|
context.blitter->blit(getPendingCommandBuffer(&context), args, "Texture upload blit");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalTexture::extendLodRangeTo(uint32_t level) {
|
void MetalTexture::updateLodRange(uint32_t level) {
|
||||||
assert_invariant(!isInRenderPass(&context));
|
assert_invariant(!isInRenderPass(&context));
|
||||||
minLod = std::min(minLod, level);
|
minLod = std::min(minLod, level);
|
||||||
maxLod = std::max(maxLod, level);
|
maxLod = std::max(maxLod, level);
|
||||||
lodTextureView = nil;
|
lodTextureView = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalTexture::setLodRange(uint32_t min, uint32_t max) {
|
void MetalTexture::updateLodRange(uint32_t min, uint32_t max) {
|
||||||
assert_invariant(!isInRenderPass(&context));
|
assert_invariant(!isInRenderPass(&context));
|
||||||
assert_invariant(min <= max);
|
assert_invariant(min <= max);
|
||||||
minLod = min;
|
minLod = std::min(minLod, min);
|
||||||
maxLod = max;
|
maxLod = std::max(maxLod, max);
|
||||||
lodTextureView = nil;
|
lodTextureView = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,11 +103,6 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
|
|||||||
return programData;
|
return programData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait() const noexcept {
|
|
||||||
std::unique_lock l(lock);
|
|
||||||
cond.wait(l, [this](){ return signaled; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if the programBinary is ready.
|
// Checks if the programBinary is ready.
|
||||||
// This is similar to std::future::wait_for(0s)
|
// This is similar to std::future::wait_for(0s)
|
||||||
bool isReady() const noexcept {
|
bool isReady() const noexcept {
|
||||||
@@ -341,23 +336,7 @@ GLuint ShaderCompilerService::getProgram(ShaderCompilerService::program_token_t&
|
|||||||
|
|
||||||
token->canceled = true;
|
token->canceled = true;
|
||||||
|
|
||||||
bool canceled = token->compiler.cancelTickOp(token);
|
token->compiler.cancelTickOp(token);
|
||||||
|
|
||||||
if (token->compiler.mShaderCompilerThreadCount) {
|
|
||||||
auto job = token->compiler.mCompilerThreadPool.dequeue(token);
|
|
||||||
if (!job) {
|
|
||||||
// The job is being executed right now. We need to wait for it to finish to avoid a
|
|
||||||
// race.
|
|
||||||
token->wait();
|
|
||||||
} else {
|
|
||||||
// The job has not been executed, but we still need to inform the callback manager in
|
|
||||||
// order for future callbacks to be successfully called.
|
|
||||||
token->compiler.mCallbackManager.put(token->handle);
|
|
||||||
}
|
|
||||||
} else if (canceled) {
|
|
||||||
// Since the tick op was canceled, we need to .put the token here.
|
|
||||||
token->compiler.mCallbackManager.put(token->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (GLuint& shader: token->gl.shaders) {
|
for (GLuint& shader: token->gl.shaders) {
|
||||||
if (shader) {
|
if (shader) {
|
||||||
@@ -683,7 +662,7 @@ void ShaderCompilerService::runAtNextTick(CompilerPriorityQueue priority,
|
|||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderCompilerService::cancelTickOp(program_token_t token) noexcept {
|
void ShaderCompilerService::cancelTickOp(program_token_t token) noexcept {
|
||||||
// We do a linear search here, but this is rare, and we know the list is pretty small.
|
// We do a linear search here, but this is rare, and we know the list is pretty small.
|
||||||
auto& ops = mRunAtNextTickOps;
|
auto& ops = mRunAtNextTickOps;
|
||||||
auto pos = std::find_if(ops.begin(), ops.end(), [&](const auto& item) {
|
auto pos = std::find_if(ops.begin(), ops.end(), [&](const auto& item) {
|
||||||
@@ -691,11 +670,9 @@ bool ShaderCompilerService::cancelTickOp(program_token_t token) noexcept {
|
|||||||
});
|
});
|
||||||
if (pos != ops.end()) {
|
if (pos != ops.end()) {
|
||||||
ops.erase(pos);
|
ops.erase(pos);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
SYSTRACE_CONTEXT();
|
SYSTRACE_CONTEXT();
|
||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCompilerService::executeTickOps() noexcept {
|
void ShaderCompilerService::executeTickOps() noexcept {
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ private:
|
|||||||
void runAtNextTick(CompilerPriorityQueue priority,
|
void runAtNextTick(CompilerPriorityQueue priority,
|
||||||
const program_token_t& token, Job job) noexcept;
|
const program_token_t& token, Job job) noexcept;
|
||||||
void executeTickOps() noexcept;
|
void executeTickOps() noexcept;
|
||||||
bool cancelTickOp(program_token_t token) noexcept;
|
void cancelTickOp(program_token_t token) noexcept;
|
||||||
// order of insertion is important
|
// order of insertion is important
|
||||||
|
|
||||||
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
|
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.buffer();
|
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
||||||
commands.acquire(src.texture);
|
commands.acquire(src.texture);
|
||||||
commands.acquire(dst.texture);
|
commands.acquire(dst.texture);
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.buffer();
|
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
||||||
commands.acquire(src.texture);
|
commands.acquire(src.texture);
|
||||||
commands.acquire(dst.texture);
|
commands.acquire(dst.texture);
|
||||||
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
||||||
@@ -197,11 +197,13 @@ void VulkanBlitter::terminate() noexcept {
|
|||||||
mDepthResolveProgram = nullptr;
|
mDepthResolveProgram = nullptr;
|
||||||
|
|
||||||
if (mTriangleBuffer) {
|
if (mTriangleBuffer) {
|
||||||
|
mTriangleBuffer->terminate();
|
||||||
delete mTriangleBuffer;
|
delete mTriangleBuffer;
|
||||||
mTriangleBuffer = nullptr;
|
mTriangleBuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mParamsBuffer) {
|
if (mParamsBuffer) {
|
||||||
|
mParamsBuffer->terminate();
|
||||||
delete mParamsBuffer;
|
delete mParamsBuffer;
|
||||||
mParamsBuffer = nullptr;
|
mParamsBuffer = nullptr;
|
||||||
}
|
}
|
||||||
@@ -255,7 +257,7 @@ void VulkanBlitter::lazyInit() noexcept {
|
|||||||
};
|
};
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.buffer();
|
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
||||||
|
|
||||||
mTriangleBuffer = new VulkanBuffer(mAllocator, mStagePool, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
mTriangleBuffer = new VulkanBuffer(mAllocator, mStagePool, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
sizeof(kTriangleVertices));
|
sizeof(kTriangleVertices));
|
||||||
@@ -276,7 +278,7 @@ void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, V
|
|||||||
lazyInit();
|
lazyInit();
|
||||||
|
|
||||||
VulkanCommandBuffer* commands = &mCommands->get();
|
VulkanCommandBuffer* commands = &mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands->buffer();
|
VkCommandBuffer const cmdbuffer = commands->cmdbuffer;
|
||||||
commands->acquire(src.texture);
|
commands->acquire(src.texture);
|
||||||
commands->acquire(dst.texture);
|
commands->acquire(dst.texture);
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,14 @@ VulkanBuffer::VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanBuffer::~VulkanBuffer() {
|
VulkanBuffer::~VulkanBuffer() {
|
||||||
|
assert_invariant(mGpuMemory == VK_NULL_HANDLE);
|
||||||
|
assert_invariant(mGpuBuffer == VK_NULL_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanBuffer::terminate() {
|
||||||
vmaDestroyBuffer(mAllocator, mGpuBuffer, mGpuMemory);
|
vmaDestroyBuffer(mAllocator, mGpuBuffer, mGpuMemory);
|
||||||
|
mGpuMemory = VK_NULL_HANDLE;
|
||||||
|
mGpuBuffer = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
|
void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, VkBufferUsageFlags usage,
|
VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, VkBufferUsageFlags usage,
|
||||||
uint32_t numBytes);
|
uint32_t numBytes);
|
||||||
~VulkanBuffer();
|
~VulkanBuffer();
|
||||||
|
void terminate();
|
||||||
void loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
|
void loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
|
||||||
uint32_t numBytes) const;
|
uint32_t numBytes) const;
|
||||||
VkBuffer getGpuBuffer() const {
|
VkBuffer getGpuBuffer() const {
|
||||||
|
|||||||
@@ -35,38 +35,31 @@ namespace filament::backend {
|
|||||||
|
|
||||||
using Timestamp = VulkanGroupMarkers::Timestamp;
|
using Timestamp = VulkanGroupMarkers::Timestamp;
|
||||||
|
|
||||||
VulkanCmdFence::VulkanCmdFence(VkFence ifence)
|
VulkanCmdFence::VulkanCmdFence(VkDevice device, bool signaled) : device(device) {
|
||||||
: fence(ifence) {
|
VkFenceCreateInfo fenceCreateInfo { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||||
|
if (signaled) {
|
||||||
|
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
}
|
||||||
|
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &fence);
|
||||||
|
|
||||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence gets
|
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence gets
|
||||||
// submitted, its status changes to VK_NOT_READY. Finally, when the GPU actually finishes
|
// submitted, its status changes to VK_NOT_READY. Finally, when the GPU actually finishes
|
||||||
// executing the command buffer, the status changes to VK_SUCCESS.
|
// executing the command buffer, the status changes to VK_SUCCESS.
|
||||||
status.store(VK_INCOMPLETE);
|
status.store(VK_INCOMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanCommandBuffer::VulkanCommandBuffer(VulkanResourceAllocator* allocator, VkDevice device,
|
VulkanCmdFence::~VulkanCmdFence() {
|
||||||
VkCommandPool pool)
|
vkDestroyFence(device, fence, VKALLOC);
|
||||||
: mResourceManager(allocator) {
|
|
||||||
// Create the low-level command buffer.
|
|
||||||
const VkCommandBufferAllocateInfo allocateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
||||||
.commandPool = pool,
|
|
||||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
// The buffer allocated here will be implicitly reset when vkBeginCommandBuffer is called.
|
|
||||||
// We don't need to deallocate since destroying the pool will free all of the buffers.
|
|
||||||
vkAllocateCommandBuffers(device, &allocateInfo, &mBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandBufferObserver::~CommandBufferObserver() {}
|
CommandBufferObserver::~CommandBufferObserver() {}
|
||||||
|
|
||||||
static VkCommandPool createPool(VkDevice device, uint32_t queueFamilyIndex) {
|
static VkCommandPool createPool(VkDevice device, uint32_t queueFamilyIndex) {
|
||||||
VkCommandPoolCreateInfo createInfo = {
|
VkCommandPoolCreateInfo createInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||||
.flags =
|
.flags =
|
||||||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||||
.queueFamilyIndex = queueFamilyIndex,
|
.queueFamilyIndex = queueFamilyIndex,
|
||||||
};
|
};
|
||||||
VkCommandPool pool;
|
VkCommandPool pool;
|
||||||
vkCreateCommandPool(device, &createInfo, VKALLOC, &pool);
|
vkCreateCommandPool(device, &createInfo, VKALLOC, &pool);
|
||||||
@@ -113,7 +106,7 @@ std::pair<std::string, Timestamp> VulkanGroupMarkers::top() const {
|
|||||||
assert_invariant(!empty());
|
assert_invariant(!empty());
|
||||||
auto const marker = mMarkers.back();
|
auto const marker = mMarkers.back();
|
||||||
#if FILAMENT_VULKAN_VERBOSE
|
#if FILAMENT_VULKAN_VERBOSE
|
||||||
auto const topTimestamp = mTimestamps.front();
|
auto const topTimestamp = mTimestamps.top();
|
||||||
return std::make_pair(marker, topTimestamp);
|
return std::make_pair(marker, topTimestamp);
|
||||||
#else
|
#else
|
||||||
return std::make_pair(marker, Timestamp{});
|
return std::make_pair(marker, Timestamp{});
|
||||||
@@ -136,13 +129,8 @@ VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFam
|
|||||||
vkCreateSemaphore(mDevice, &sci, nullptr, &semaphore);
|
vkCreateSemaphore(mDevice, &sci, nullptr, &semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFenceCreateInfo fenceCreateInfo{.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
|
||||||
for (auto& fence: mFences) {
|
|
||||||
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < CAPACITY; ++i) {
|
for (size_t i = 0; i < CAPACITY; ++i) {
|
||||||
mStorage[i] = std::make_unique<VulkanCommandBuffer>(allocator, mDevice, mPool);
|
mStorage[i] = std::make_unique<VulkanCommandBuffer>(allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +138,9 @@ VulkanCommands::~VulkanCommands() {
|
|||||||
wait();
|
wait();
|
||||||
gc();
|
gc();
|
||||||
vkDestroyCommandPool(mDevice, mPool, VKALLOC);
|
vkDestroyCommandPool(mDevice, mPool, VKALLOC);
|
||||||
for (VkSemaphore sema: mSubmissionSignals) {
|
for (VkSemaphore sema : mSubmissionSignals) {
|
||||||
vkDestroySemaphore(mDevice, sema, VKALLOC);
|
vkDestroySemaphore(mDevice, sema, VKALLOC);
|
||||||
}
|
}
|
||||||
for (VkFence fence: mFences) {
|
|
||||||
vkDestroyFence(mDevice, fence, VKALLOC);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanCommandBuffer& VulkanCommands::get() {
|
VulkanCommandBuffer& VulkanCommands::get() {
|
||||||
@@ -166,11 +151,11 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
|||||||
// If we ran out of available command buffers, stall until one finishes. This is very rare.
|
// If we ran out of available command buffers, stall until one finishes. This is very rare.
|
||||||
// It occurs only when Filament invokes commit() or endFrame() a large number of times without
|
// It occurs only when Filament invokes commit() or endFrame() a large number of times without
|
||||||
// presenting the swap chain or waiting on a fence.
|
// presenting the swap chain or waiting on a fence.
|
||||||
while (mAvailableBufferCount == 0) {
|
while (mAvailableCount == 0) {
|
||||||
#if VK_REPORT_STALLS
|
#if VK_REPORT_STALLS
|
||||||
slog.i << "VulkanCommands has stalled. "
|
slog.i << "VulkanCommands has stalled. "
|
||||||
<< "If this occurs frequently, consider increasing VK_MAX_COMMAND_BUFFERS."
|
<< "If this occurs frequently, consider increasing VK_MAX_COMMAND_BUFFERS."
|
||||||
<< io::endl;
|
<< io::endl;
|
||||||
#endif
|
#endif
|
||||||
wait();
|
wait();
|
||||||
gc();
|
gc();
|
||||||
@@ -180,7 +165,7 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
|||||||
// Find an available slot.
|
// Find an available slot.
|
||||||
for (size_t i = 0; i < CAPACITY; ++i) {
|
for (size_t i = 0; i < CAPACITY; ++i) {
|
||||||
auto wrapper = mStorage[i].get();
|
auto wrapper = mStorage[i].get();
|
||||||
if (wrapper->buffer() == VK_NULL_HANDLE) {
|
if (wrapper->cmdbuffer == VK_NULL_HANDLE) {
|
||||||
mCurrentCommandBufferIndex = static_cast<int8_t>(i);
|
mCurrentCommandBufferIndex = static_cast<int8_t>(i);
|
||||||
currentbuf = wrapper;
|
currentbuf = wrapper;
|
||||||
break;
|
break;
|
||||||
@@ -188,19 +173,28 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_invariant(currentbuf);
|
assert_invariant(currentbuf);
|
||||||
mAvailableBufferCount--;
|
--mAvailableCount;
|
||||||
|
|
||||||
|
// Create the low-level command buffer.
|
||||||
|
const VkCommandBufferAllocateInfo allocateInfo {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||||
|
.commandPool = mPool,
|
||||||
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||||
|
.commandBufferCount = 1
|
||||||
|
};
|
||||||
|
vkAllocateCommandBuffers(mDevice, &allocateInfo, ¤tbuf->cmdbuffer);
|
||||||
|
|
||||||
// Note that the fence wrapper uses shared_ptr because a DriverAPI fence can also have ownership
|
// Note that the fence wrapper uses shared_ptr because a DriverAPI fence can also have ownership
|
||||||
// over it. The destruction of the low-level fence occurs either in VulkanCommands::gc(), or in
|
// over it. The destruction of the low-level fence occurs either in VulkanCommands::gc(), or in
|
||||||
// VulkanDriver::destroyFence(), both of which are safe spots.
|
// VulkanDriver::destroyFence(), both of which are safe spots.
|
||||||
currentbuf->fence = std::make_shared<VulkanCmdFence>(mFences[mCurrentCommandBufferIndex]);
|
currentbuf->fence = std::make_shared<VulkanCmdFence>(mDevice);
|
||||||
|
|
||||||
// Begin writing into the command buffer.
|
// Begin writing into the command buffer.
|
||||||
const VkCommandBufferBeginInfo binfo{
|
const VkCommandBufferBeginInfo binfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||||
};
|
};
|
||||||
vkBeginCommandBuffer(currentbuf->buffer(), &binfo);
|
vkBeginCommandBuffer(currentbuf->cmdbuffer, &binfo);
|
||||||
|
|
||||||
// Notify the observer that a new command buffer has been activated.
|
// Notify the observer that a new command buffer has been activated.
|
||||||
if (mObserver) {
|
if (mObserver) {
|
||||||
@@ -213,6 +207,7 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
|||||||
auto [marker, time] = mCarriedOverMarkers->pop();
|
auto [marker, time] = mCarriedOverMarkers->pop();
|
||||||
pushGroupMarker(marker.c_str(), time);
|
pushGroupMarker(marker.c_str(), time);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *currentbuf;
|
return *currentbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,24 +217,11 @@ bool VulkanCommands::flush() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before actually submitting, we need to pop any leftover group markers.
|
|
||||||
// Note that this needs to occur before vkEndCommandBuffer.
|
|
||||||
while (mGroupMarkers && !mGroupMarkers->empty()) {
|
|
||||||
if (!mCarriedOverMarkers) {
|
|
||||||
mCarriedOverMarkers = std::make_unique<VulkanGroupMarkers>();
|
|
||||||
}
|
|
||||||
auto const [marker, time] = mGroupMarkers->top();
|
|
||||||
mCarriedOverMarkers->push(marker, time);
|
|
||||||
// We still need to call through to vkCmdEndDebugUtilsLabelEXT.
|
|
||||||
popGroupMarker();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int8_t const index = mCurrentCommandBufferIndex;
|
int8_t const index = mCurrentCommandBufferIndex;
|
||||||
VulkanCommandBuffer const* currentbuf = mStorage[index].get();
|
VulkanCommandBuffer const* currentbuf = mStorage[index].get();
|
||||||
VkSemaphore const renderingFinished = mSubmissionSignals[index];
|
VkSemaphore const renderingFinished = mSubmissionSignals[index];
|
||||||
|
|
||||||
vkEndCommandBuffer(currentbuf->buffer());
|
vkEndCommandBuffer(currentbuf->cmdbuffer);
|
||||||
|
|
||||||
// If the injected semaphore is an "image available" semaphore that has not yet been signaled,
|
// If the injected semaphore is an "image available" semaphore that has not yet been signaled,
|
||||||
// it is sometimes fine to start executing commands anyway, as along as we stall the GPU at the
|
// it is sometimes fine to start executing commands anyway, as along as we stall the GPU at the
|
||||||
@@ -248,26 +230,24 @@ bool VulkanCommands::flush() {
|
|||||||
// the only safe option because the previously submitted command buffer might have set up some
|
// the only safe option because the previously submitted command buffer might have set up some
|
||||||
// state that the new command buffer depends on.
|
// state that the new command buffer depends on.
|
||||||
VkPipelineStageFlags waitDestStageMasks[2] = {
|
VkPipelineStageFlags waitDestStageMasks[2] = {
|
||||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkSemaphore signals[2] = {
|
VkSemaphore signals[2] = {
|
||||||
VK_NULL_HANDLE,
|
VK_NULL_HANDLE,
|
||||||
VK_NULL_HANDLE,
|
VK_NULL_HANDLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkCommandBuffer const cmdbuffer = currentbuf->buffer();
|
VkSubmitInfo submitInfo {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||||
VkSubmitInfo submitInfo{
|
.waitSemaphoreCount = 0,
|
||||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
.pWaitSemaphores = signals,
|
||||||
.waitSemaphoreCount = 0,
|
.pWaitDstStageMask = waitDestStageMasks,
|
||||||
.pWaitSemaphores = signals,
|
.commandBufferCount = 1,
|
||||||
.pWaitDstStageMask = waitDestStageMasks,
|
.pCommandBuffers = ¤tbuf->cmdbuffer,
|
||||||
.commandBufferCount = 1,
|
.signalSemaphoreCount = 1u,
|
||||||
.pCommandBuffers = &cmdbuffer,
|
.pSignalSemaphores = &renderingFinished,
|
||||||
.signalSemaphoreCount = 1u,
|
|
||||||
.pSignalSemaphores = &renderingFinished,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mSubmissionSignal) {
|
if (mSubmissionSignal) {
|
||||||
@@ -284,13 +264,23 @@ bool VulkanCommands::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FILAMENT_VULKAN_VERBOSE
|
#if FILAMENT_VULKAN_VERBOSE
|
||||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
slog.i << "Submitting cmdbuffer=" << currentbuf->cmdbuffer
|
||||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||||
<< " signal=" << renderingFinished
|
<< " signal=" << renderingFinished
|
||||||
<< " fence=" << currentbuf->fence->fence
|
<< io::endl;
|
||||||
<< utils::io::endl;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Before actually submitting, we need to pop any leftover group markers.
|
||||||
|
while (mGroupMarkers && !mGroupMarkers->empty()) {
|
||||||
|
if (!mCarriedOverMarkers) {
|
||||||
|
mCarriedOverMarkers = std::make_unique<VulkanGroupMarkers>();
|
||||||
|
}
|
||||||
|
auto const [marker, time] = mGroupMarkers->top();
|
||||||
|
mCarriedOverMarkers->push(marker, time);
|
||||||
|
// We still need to call through to vkCmdEndDebugUtilsLabelEXT.
|
||||||
|
popGroupMarker();
|
||||||
|
}
|
||||||
|
|
||||||
auto& cmdfence = currentbuf->fence;
|
auto& cmdfence = currentbuf->fence;
|
||||||
std::unique_lock<utils::Mutex> lock(cmdfence->mutex);
|
std::unique_lock<utils::Mutex> lock(cmdfence->mutex);
|
||||||
cmdfence->status.store(VK_NOT_READY);
|
cmdfence->status.store(VK_NOT_READY);
|
||||||
@@ -300,7 +290,7 @@ bool VulkanCommands::flush() {
|
|||||||
|
|
||||||
#if FILAMENT_VULKAN_VERBOSE
|
#if FILAMENT_VULKAN_VERBOSE
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
utils::slog.d << "Failed command buffer submission result: " << result << utils::io::endl;
|
utils::slog.d <<"Failed command buffer submission result: " << result << utils::io::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
assert_invariant(result == VK_SUCCESS);
|
assert_invariant(result == VK_SUCCESS);
|
||||||
@@ -333,45 +323,44 @@ void VulkanCommands::wait() {
|
|||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (size_t i = 0; i < CAPACITY; i++) {
|
for (size_t i = 0; i < CAPACITY; i++) {
|
||||||
auto wrapper = mStorage[i].get();
|
auto wrapper = mStorage[i].get();
|
||||||
if (wrapper->buffer() != VK_NULL_HANDLE
|
if (wrapper->cmdbuffer != VK_NULL_HANDLE
|
||||||
&& mCurrentCommandBufferIndex != static_cast<int8_t>(i)) {
|
&& mCurrentCommandBufferIndex != static_cast<int8_t>(i)) {
|
||||||
fences[count++] = wrapper->fence->fence;
|
fences[count++] = wrapper->fence->fence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
|
vkWaitForFences(mDevice, count, fences, VK_TRUE, UINT64_MAX);
|
||||||
updateFences();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommands::gc() {
|
void VulkanCommands::gc() {
|
||||||
VkFence fences[CAPACITY];
|
VkCommandBuffer buffers[CAPACITY];
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < CAPACITY; i++) {
|
for (size_t i = 0; i < CAPACITY; i++) {
|
||||||
auto wrapper = mStorage[i].get();
|
auto wrapper = mStorage[i].get();
|
||||||
if (wrapper->buffer() == VK_NULL_HANDLE) {
|
if (wrapper->cmdbuffer == VK_NULL_HANDLE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
VkResult const result = vkGetFenceStatus(mDevice, wrapper->fence->fence);
|
VkResult const result = vkWaitForFences(mDevice, 1, &wrapper->fence->fence, VK_TRUE, 0);
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fences[count++] = wrapper->fence->fence;
|
buffers[count++] = wrapper->cmdbuffer;
|
||||||
|
wrapper->cmdbuffer = VK_NULL_HANDLE;
|
||||||
wrapper->fence->status.store(VK_SUCCESS);
|
wrapper->fence->status.store(VK_SUCCESS);
|
||||||
wrapper->reset();
|
wrapper->fence.reset();
|
||||||
mAvailableBufferCount++;
|
wrapper->clearResources();
|
||||||
|
++mAvailableCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
vkResetFences(mDevice, count, fences);
|
vkFreeCommandBuffers(mDevice, mPool, count, buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommands::updateFences() {
|
void VulkanCommands::updateFences() {
|
||||||
for (size_t i = 0; i < CAPACITY; i++) {
|
for (size_t i = 0; i < CAPACITY; i++) {
|
||||||
auto wrapper = mStorage[i].get();
|
auto wrapper = mStorage[i].get();
|
||||||
if (wrapper->buffer() != VK_NULL_HANDLE) {
|
if (wrapper->cmdbuffer != VK_NULL_HANDLE) {
|
||||||
VulkanCmdFence* fence = wrapper->fence.get();
|
VulkanCmdFence* fence = wrapper->fence.get();
|
||||||
if (fence) {
|
if (fence) {
|
||||||
VkResult status = vkGetFenceStatus(mDevice, fence->fence);
|
VkResult status = vkGetFenceStatus(mDevice, fence->fence);
|
||||||
@@ -392,7 +381,7 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: Add group marker color to the Driver API
|
// TODO: Add group marker color to the Driver API
|
||||||
VkCommandBuffer const cmdbuffer = get().buffer();
|
const VkCommandBuffer cmdbuffer = get().cmdbuffer;
|
||||||
|
|
||||||
if (!mGroupMarkers) {
|
if (!mGroupMarkers) {
|
||||||
mGroupMarkers = std::make_unique<VulkanGroupMarkers>();
|
mGroupMarkers = std::make_unique<VulkanGroupMarkers>();
|
||||||
@@ -417,19 +406,19 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommands::popGroupMarker() {
|
void VulkanCommands::popGroupMarker() {
|
||||||
assert_invariant(mGroupMarkers);
|
assert_invariant(mGroupMarkers);
|
||||||
|
|
||||||
if (!mGroupMarkers->empty()) {
|
if (!mGroupMarkers->empty()) {
|
||||||
VkCommandBuffer const cmdbuffer = get().buffer();
|
const VkCommandBuffer cmdbuffer = get().cmdbuffer;
|
||||||
#if FILAMENT_VULKAN_VERBOSE
|
#if FILAMENT_VULKAN_VERBOSE
|
||||||
auto const [marker, startTime] = mGroupMarkers->pop();
|
auto const [marker, startTime] = mGroupMarkers->pop();
|
||||||
auto const endTime = std::chrono::high_resolution_clock::now();
|
auto const endTime = std::chrono::high_resolution_clock::now();
|
||||||
std::chrono::duration<double> diff = endTime - startTime;
|
std::chrono::duration<double> diff = endTime - startTime;
|
||||||
utils::slog.d << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms\n"
|
utils::slog.d << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms\n"
|
||||||
<< utils::io::flush;
|
<< utils::io::flush;
|
||||||
#else
|
#else
|
||||||
mGroupMarkers->pop();
|
mGroupMarkers->pop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mContext->isDebugUtilsSupported()) {
|
if (mContext->isDebugUtilsSupported()) {
|
||||||
vkCmdEndDebugUtilsLabelEXT(cmdbuffer);
|
vkCmdEndDebugUtilsLabelEXT(cmdbuffer);
|
||||||
@@ -445,7 +434,7 @@ void VulkanCommands::popGroupMarker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommands::insertEventMarker(char const* string, uint32_t len) {
|
void VulkanCommands::insertEventMarker(char const* string, uint32_t len) {
|
||||||
VkCommandBuffer const cmdbuffer = get().buffer();
|
VkCommandBuffer const cmdbuffer = get().cmdbuffer;
|
||||||
if (mContext->isDebugUtilsSupported()) {
|
if (mContext->isDebugUtilsSupported()) {
|
||||||
VkDebugUtilsLabelEXT labelInfo = {
|
VkDebugUtilsLabelEXT labelInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||||
@@ -455,9 +444,9 @@ void VulkanCommands::insertEventMarker(char const* string, uint32_t len) {
|
|||||||
vkCmdInsertDebugUtilsLabelEXT(cmdbuffer, &labelInfo);
|
vkCmdInsertDebugUtilsLabelEXT(cmdbuffer, &labelInfo);
|
||||||
} else if (mContext->isDebugMarkersSupported()) {
|
} else if (mContext->isDebugMarkersSupported()) {
|
||||||
VkDebugMarkerMarkerInfoEXT markerInfo = {
|
VkDebugMarkerMarkerInfoEXT markerInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT,
|
.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT,
|
||||||
.pMarkerName = string,
|
.pMarkerName = string,
|
||||||
.color = {0.0f, 1.0f, 0.0f, 1.0f},
|
.color = {0.0f, 1.0f, 0.0f, 1.0f},
|
||||||
};
|
};
|
||||||
vkCmdDebugMarkerInsertEXT(cmdbuffer, &markerInfo);
|
vkCmdDebugMarkerInsertEXT(cmdbuffer, &markerInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,9 @@ private:
|
|||||||
|
|
||||||
// Wrapper to enable use of shared_ptr for implementing shared ownership of low-level Vulkan fences.
|
// Wrapper to enable use of shared_ptr for implementing shared ownership of low-level Vulkan fences.
|
||||||
struct VulkanCmdFence {
|
struct VulkanCmdFence {
|
||||||
VulkanCmdFence(VkFence ifence);
|
VulkanCmdFence(VkDevice device, bool signaled = false);
|
||||||
~VulkanCmdFence() = default;
|
~VulkanCmdFence();
|
||||||
|
const VkDevice device;
|
||||||
VkFence fence;
|
VkFence fence;
|
||||||
utils::Condition condition;
|
utils::Condition condition;
|
||||||
utils::Mutex mutex;
|
utils::Mutex mutex;
|
||||||
@@ -70,10 +71,13 @@ struct VulkanCmdFence {
|
|||||||
// DriverApi fence object and should not be destroyed until both the DriverApi object is freed and
|
// DriverApi fence object and should not be destroyed until both the DriverApi object is freed and
|
||||||
// we're done waiting on the most recent submission of the given command buffer.
|
// we're done waiting on the most recent submission of the given command buffer.
|
||||||
struct VulkanCommandBuffer {
|
struct VulkanCommandBuffer {
|
||||||
VulkanCommandBuffer(VulkanResourceAllocator* allocator, VkDevice device, VkCommandPool pool);
|
VulkanCommandBuffer(VulkanResourceAllocator* allocator)
|
||||||
|
: mResourceManager(allocator) {}
|
||||||
|
|
||||||
VulkanCommandBuffer(VulkanCommandBuffer const&) = delete;
|
VulkanCommandBuffer(VulkanCommandBuffer const&) = delete;
|
||||||
VulkanCommandBuffer& operator=(VulkanCommandBuffer const&) = delete;
|
VulkanCommandBuffer& operator=(VulkanCommandBuffer const&) = delete;
|
||||||
|
VkCommandBuffer cmdbuffer = VK_NULL_HANDLE;
|
||||||
|
std::shared_ptr<VulkanCmdFence> fence;
|
||||||
|
|
||||||
inline void acquire(VulkanResource* resource) {
|
inline void acquire(VulkanResource* resource) {
|
||||||
mResourceManager.acquire(resource);
|
mResourceManager.acquire(resource);
|
||||||
@@ -83,23 +87,12 @@ struct VulkanCommandBuffer {
|
|||||||
mResourceManager.acquire(srcResources);
|
mResourceManager.acquire(srcResources);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void reset() {
|
inline void clearResources() {
|
||||||
fence.reset();
|
|
||||||
mResourceManager.clear();
|
mResourceManager.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VkCommandBuffer buffer() const {
|
|
||||||
if (fence) {
|
|
||||||
return mBuffer;
|
|
||||||
}
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<VulkanCmdFence> fence;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VulkanAcquireOnlyResourceManager mResourceManager;
|
VulkanAcquireOnlyResourceManager mResourceManager;
|
||||||
VkCommandBuffer mBuffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allows classes to be notified after a new command buffer has been activated.
|
// Allows classes to be notified after a new command buffer has been activated.
|
||||||
@@ -191,9 +184,8 @@ class VulkanCommands {
|
|||||||
VkSemaphore mSubmissionSignal = {};
|
VkSemaphore mSubmissionSignal = {};
|
||||||
VkSemaphore mInjectedSignal = {};
|
VkSemaphore mInjectedSignal = {};
|
||||||
utils::FixedCapacityVector<std::unique_ptr<VulkanCommandBuffer>> mStorage;
|
utils::FixedCapacityVector<std::unique_ptr<VulkanCommandBuffer>> mStorage;
|
||||||
VkFence mFences[CAPACITY] = {};
|
|
||||||
VkSemaphore mSubmissionSignals[CAPACITY] = {};
|
VkSemaphore mSubmissionSignals[CAPACITY] = {};
|
||||||
uint8_t mAvailableBufferCount = CAPACITY;
|
size_t mAvailableCount = CAPACITY;
|
||||||
CommandBufferObserver* mObserver = nullptr;
|
CommandBufferObserver* mObserver = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<VulkanGroupMarkers> mGroupMarkers;
|
std::unique_ptr<VulkanGroupMarkers> mGroupMarkers;
|
||||||
|
|||||||
@@ -117,9 +117,8 @@ void VulkanTimestamps::beginQuery(VulkanCommandBuffer const* commands,
|
|||||||
VulkanTimerQuery* query) {
|
VulkanTimerQuery* query) {
|
||||||
uint32_t const index = query->getStartingQueryIndex();
|
uint32_t const index = query->getStartingQueryIndex();
|
||||||
|
|
||||||
auto const cmdbuffer = commands->buffer();
|
vkCmdResetQueryPool(commands->cmdbuffer, mPool, index, 2);
|
||||||
vkCmdResetQueryPool(cmdbuffer, mPool, index, 2);
|
vkCmdWriteTimestamp(commands->cmdbuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mPool, index);
|
||||||
vkCmdWriteTimestamp(cmdbuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mPool, index);
|
|
||||||
|
|
||||||
// We stash this because getResult might come before the query is actually processed.
|
// We stash this because getResult might come before the query is actually processed.
|
||||||
query->setFence(commands->fence);
|
query->setFence(commands->fence);
|
||||||
@@ -128,7 +127,7 @@ void VulkanTimestamps::beginQuery(VulkanCommandBuffer const* commands,
|
|||||||
void VulkanTimestamps::endQuery(VulkanCommandBuffer const* commands,
|
void VulkanTimestamps::endQuery(VulkanCommandBuffer const* commands,
|
||||||
VulkanTimerQuery const* query) {
|
VulkanTimerQuery const* query) {
|
||||||
uint32_t const index = query->getStoppingQueryIndex();
|
uint32_t const index = query->getStoppingQueryIndex();
|
||||||
vkCmdWriteTimestamp(commands->buffer(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mPool, index);
|
vkCmdWriteTimestamp(commands->cmdbuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mPool, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanTimestamps::QueryResult VulkanTimestamps::getResult(VulkanTimerQuery const* query) {
|
VulkanTimestamps::QueryResult VulkanTimestamps::getResult(VulkanTimerQuery const* query) {
|
||||||
|
|||||||
@@ -526,22 +526,21 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
|||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||||
}
|
}
|
||||||
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
|
mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext, mAllocator,
|
||||||
mAllocator, mCommands.get(), mStagePool, nativeWindow, flags);
|
mCommands.get(), mStagePool, nativeWindow, flags);
|
||||||
mResourceManager.acquire(swapChain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
||||||
uint32_t height, uint64_t flags) {
|
uint32_t height, uint64_t flags) {
|
||||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 &&
|
||||||
|
!isSRGBSwapChainSupported()) {
|
||||||
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||||
}
|
}
|
||||||
assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions.");
|
assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions.");
|
||||||
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
|
mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext, mAllocator,
|
||||||
mAllocator, mCommands.get(), mStagePool, nullptr, flags, VkExtent2D{width, height});
|
mCommands.get(), mStagePool, nullptr, flags, VkExtent2D{width, height});
|
||||||
mResourceManager.acquire(swapChain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||||
@@ -691,15 +690,16 @@ FenceStatus VulkanDriver::getFenceStatus(Handle<HwFence> fh) {
|
|||||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted".
|
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted".
|
||||||
// When this fence gets submitted, its status changes to VK_NOT_READY.
|
// When this fence gets submitted, its status changes to VK_NOT_READY.
|
||||||
std::unique_lock<utils::Mutex> lock(cmdfence->mutex);
|
std::unique_lock<utils::Mutex> lock(cmdfence->mutex);
|
||||||
if (cmdfence->status.load() == VK_SUCCESS) {
|
if (cmdfence->status.load() == VK_INCOMPLETE) {
|
||||||
return FenceStatus::CONDITION_SATISFIED;
|
// This will obviously timeout if Filament creates a fence and immediately waits on it
|
||||||
|
// without calling endFrame() or commit().
|
||||||
|
cmdfence->condition.wait(lock);
|
||||||
|
} else {
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
VkResult result =
|
||||||
// Two other states are possible:
|
vkWaitForFences(mPlatform->getDevice(), 1, &cmdfence->fence, VK_TRUE, 0);
|
||||||
// - VK_INCOMPLETE: the corresponding buffer has not yet been submitted.
|
return result == VK_SUCCESS ? FenceStatus::CONDITION_SATISFIED : FenceStatus::TIMEOUT_EXPIRED;
|
||||||
// - VK_NOT_READY: the buffer has been submitted but not yet signaled.
|
|
||||||
// In either case, we return TIMEOUT_EXPIRED to indicate the fence has not been signaled.
|
|
||||||
return FenceStatus::TIMEOUT_EXPIRED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -872,7 +872,7 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
|
|||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
auto ib = mResourceAllocator.handle_cast<VulkanIndexBuffer*>(ibh);
|
auto ib = mResourceAllocator.handle_cast<VulkanIndexBuffer*>(ibh);
|
||||||
commands.acquire(ib);
|
commands.acquire(ib);
|
||||||
ib->buffer.loadFromCpu(commands.buffer(), p.buffer, byteOffset, p.size);
|
ib->buffer.loadFromCpu(commands.cmdbuffer, p.buffer, byteOffset, p.size);
|
||||||
|
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
@@ -883,7 +883,7 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
|
|||||||
|
|
||||||
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
|
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
|
||||||
commands.acquire(bo);
|
commands.acquire(bo);
|
||||||
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
|
bo->buffer.loadFromCpu(commands.cmdbuffer, bd.buffer, byteOffset, bd.size);
|
||||||
|
|
||||||
scheduleDestroy(std::move(bd));
|
scheduleDestroy(std::move(bd));
|
||||||
}
|
}
|
||||||
@@ -894,7 +894,7 @@ void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
|
|||||||
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
|
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
|
||||||
commands.acquire(bo);
|
commands.acquire(bo);
|
||||||
// TODO: implement unsynchronized version
|
// TODO: implement unsynchronized version
|
||||||
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
|
bo->buffer.loadFromCpu(commands.cmdbuffer, bd.buffer, byteOffset, bd.size);
|
||||||
mResourceManager.acquire(bo);
|
mResourceManager.acquire(bo);
|
||||||
scheduleDestroy(std::move(bd));
|
scheduleDestroy(std::move(bd));
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1020,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
|||||||
// the non-sampling case.
|
// the non-sampling case.
|
||||||
bool samplingDepthAttachment = false;
|
bool samplingDepthAttachment = false;
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.buffer();
|
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
||||||
|
|
||||||
UTILS_NOUNROLL
|
UTILS_NOUNROLL
|
||||||
for (uint8_t samplerGroupIdx = 0; samplerGroupIdx < Program::SAMPLER_BINDING_COUNT;
|
for (uint8_t samplerGroupIdx = 0; samplerGroupIdx < Program::SAMPLER_BINDING_COUNT;
|
||||||
@@ -1246,7 +1246,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
|||||||
|
|
||||||
void VulkanDriver::endRenderPass(int) {
|
void VulkanDriver::endRenderPass(int) {
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer cmdbuffer = commands.buffer();
|
VkCommandBuffer cmdbuffer = commands.cmdbuffer;
|
||||||
vkCmdEndRenderPass(cmdbuffer);
|
vkCmdEndRenderPass(cmdbuffer);
|
||||||
|
|
||||||
VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget;
|
VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget;
|
||||||
@@ -1298,7 +1298,7 @@ void VulkanDriver::nextSubpass(int) {
|
|||||||
assert_invariant(renderTarget);
|
assert_invariant(renderTarget);
|
||||||
assert_invariant(mCurrentRenderPass.params.subpassMask);
|
assert_invariant(mCurrentRenderPass.params.subpassMask);
|
||||||
|
|
||||||
vkCmdNextSubpass(mCommands->get().buffer(), VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdNextSubpass(mCommands->get().cmdbuffer, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass,
|
mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass,
|
||||||
++mCurrentRenderPass.currentSubpass);
|
++mCurrentRenderPass.currentSubpass);
|
||||||
@@ -1483,7 +1483,7 @@ void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, V
|
|||||||
void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
|
void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
|
||||||
const uint32_t instanceCount) {
|
const uint32_t instanceCount) {
|
||||||
VulkanCommandBuffer* commands = &mCommands->get();
|
VulkanCommandBuffer* commands = &mCommands->get();
|
||||||
VkCommandBuffer cmdbuffer = commands->buffer();
|
VkCommandBuffer cmdbuffer = commands->cmdbuffer;
|
||||||
const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast<VulkanRenderPrimitive*>(rph);
|
const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast<VulkanRenderPrimitive*>(rph);
|
||||||
|
|
||||||
Handle<HwProgram> programHandle = pipelineState.program;
|
Handle<HwProgram> programHandle = pipelineState.program;
|
||||||
|
|||||||
@@ -89,26 +89,21 @@ VulkanProgram::VulkanProgram(VkDevice device, const Program& builder) noexcept
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < specializationConstants.size(); i++) {
|
for (size_t i = 0; i < specializationConstants.size(); i++) {
|
||||||
uint32_t const offset = uint32_t(i) * 4;
|
const uint32_t offset = uint32_t(i) * 4;
|
||||||
pEntries[i] = {
|
std::visit([&](auto&& arg) {
|
||||||
.constantID = specializationConstants[i].id,
|
using T = std::decay_t<decltype(arg)>;
|
||||||
.offset = offset,
|
pEntries[i] = {
|
||||||
// Note that bools are 4-bytes in Vulkan
|
.constantID = specializationConstants[i].id,
|
||||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBool32.html
|
.offset = offset,
|
||||||
.size = 4,
|
// Turns out vulkan expects the size of bool to be 4 (verified through
|
||||||
};
|
// validation layer). So all expected types are of 4 bytes.
|
||||||
|
.size = 4,
|
||||||
using SpecConstant = Program::SpecializationConstant::Type;
|
};
|
||||||
char const* addr = (char*)pData + offset;
|
T* const addr = (T*)((char*)pData + offset);
|
||||||
SpecConstant const& arg = specializationConstants[i].value;
|
*addr = arg;
|
||||||
if (std::holds_alternative<bool>(arg)) {
|
}, specializationConstants[i].value);
|
||||||
*((VkBool32*)addr) = std::get<bool>(arg) ? VK_TRUE : VK_FALSE;
|
|
||||||
} else if (std::holds_alternative<float>(arg)) {
|
|
||||||
*((float*)addr) = std::get<float>(arg);
|
|
||||||
} else {
|
|
||||||
*((int32_t*)addr) = std::get<int32_t>(arg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle.specializationInfos = pInfo;
|
bundle.specializationInfos = pInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ struct VulkanVertexBuffer : public HwVertexBuffer, VulkanResource {
|
|||||||
|
|
||||||
void setBuffer(VulkanBufferObject* bufferObject, uint32_t index);
|
void setBuffer(VulkanBufferObject* bufferObject, uint32_t index);
|
||||||
|
|
||||||
|
inline void terminate() {
|
||||||
|
mResources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
utils::FixedCapacityVector<VulkanBuffer const*> buffers;
|
utils::FixedCapacityVector<VulkanBuffer const*> buffers;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -110,6 +114,9 @@ struct VulkanIndexBuffer : public HwIndexBuffer, VulkanResource {
|
|||||||
buffer(allocator, stagePool, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount),
|
buffer(allocator, stagePool, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount),
|
||||||
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32) {}
|
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32) {}
|
||||||
|
|
||||||
|
void terminate() {
|
||||||
|
buffer.terminate();
|
||||||
|
}
|
||||||
VulkanBuffer buffer;
|
VulkanBuffer buffer;
|
||||||
const VkIndexType indexType;
|
const VkIndexType indexType;
|
||||||
};
|
};
|
||||||
@@ -117,7 +124,9 @@ struct VulkanIndexBuffer : public HwIndexBuffer, VulkanResource {
|
|||||||
struct VulkanBufferObject : public HwBufferObject, VulkanResource {
|
struct VulkanBufferObject : public HwBufferObject, VulkanResource {
|
||||||
VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, uint32_t byteCount,
|
VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, uint32_t byteCount,
|
||||||
BufferObjectBinding bindingType, BufferUsage usage);
|
BufferObjectBinding bindingType, BufferUsage usage);
|
||||||
|
void terminate() {
|
||||||
|
buffer.terminate();
|
||||||
|
}
|
||||||
VulkanBuffer buffer;
|
VulkanBuffer buffer;
|
||||||
const BufferObjectBinding bindingType;
|
const BufferObjectBinding bindingType;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ bool VulkanPipelineCache::bindDescriptors(VkCommandBuffer cmdbuffer) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) noexcept {
|
bool VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) noexcept {
|
||||||
VkCommandBuffer const cmdbuffer = commands->buffer();
|
VkCommandBuffer const cmdbuffer = commands->cmdbuffer;
|
||||||
|
|
||||||
PipelineMap::iterator pipelineIter = mPipelines.find(mPipelineRequirements);
|
PipelineMap::iterator pipelineIter = mPipelines.find(mPipelineRequirements);
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ void VulkanPipelineCache::terminate() noexcept {
|
|||||||
mDummyMemory = VK_NULL_HANDLE;
|
mDummyMemory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& cmdbuffer) {
|
||||||
// The timestamp associated with a given cache entry represents "time" as a count of flush
|
// The timestamp associated with a given cache entry represents "time" as a count of flush
|
||||||
// events since the cache was constructed. If any cache entry was most recently used over
|
// events since the cache was constructed. If any cache entry was most recently used over
|
||||||
// VK_MAX_PIPELINE_AGE flush events in the past, then we can be sure that it is no longer
|
// VK_MAX_PIPELINE_AGE flush events in the past, then we can be sure that it is no longer
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ public:
|
|||||||
template<typename D, typename B>
|
template<typename D, typename B>
|
||||||
inline void destruct(Handle<B> handle) noexcept {
|
inline void destruct(Handle<B> handle) noexcept {
|
||||||
auto obj = handle_cast<D*>(handle);
|
auto obj = handle_cast<D*>(handle);
|
||||||
|
if constexpr (std::is_base_of_v<VulkanIndexBuffer, D>
|
||||||
|
|| std::is_base_of_v<VulkanBufferObject, D>) {
|
||||||
|
obj->terminate();
|
||||||
|
}
|
||||||
TRACK_DECREMENT();
|
TRACK_DECREMENT();
|
||||||
mHandleAllocatorImpl.deallocate(handle, obj);
|
mHandleAllocatorImpl.deallocate(handle, obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,10 +164,6 @@ private:
|
|||||||
public:
|
public:
|
||||||
using const_iterator = FixedSizeArray::const_iterator;
|
using const_iterator = FixedSizeArray::const_iterator;
|
||||||
|
|
||||||
inline ~FixedCapacityResourceSet() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const_iterator begin() {
|
inline const_iterator begin() {
|
||||||
if (mInd == 0) {
|
if (mInd == 0) {
|
||||||
return mArray.cend();
|
return mArray.cend();
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
|||||||
assert_invariant(result == VK_SUCCESS);
|
assert_invariant(result == VK_SUCCESS);
|
||||||
|
|
||||||
VkImageAspectFlags const aspectFlags = getImageAspect(vkformat);
|
VkImageAspectFlags const aspectFlags = getImageAspect(vkformat);
|
||||||
VkCommandBuffer const cmdbuffer = mCommands->get().buffer();
|
const VkCommandBuffer cmdbuffer = mCommands->get().cmdbuffer;
|
||||||
|
|
||||||
// We use VK_IMAGE_LAYOUT_GENERAL here because the spec says:
|
// We use VK_IMAGE_LAYOUT_GENERAL here because the spec says:
|
||||||
// "Host access to image memory is only well-defined for linear images and for image
|
// "Host access to image memory is only well-defined for linear images and for image
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ void VulkanSwapChain::update() {
|
|||||||
|
|
||||||
void VulkanSwapChain::present() {
|
void VulkanSwapChain::present() {
|
||||||
if (!mHeadless) {
|
if (!mHeadless) {
|
||||||
VkCommandBuffer const cmdbuf = mCommands->get().buffer();
|
VkCommandBuffer const cmdbuf = mCommands->get().cmdbuffer;
|
||||||
VkImageSubresourceRange const subresources{
|
VkImageSubresourceRange const subresources{
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
VkImageSubresourceRange range = { getImageAspect(), 0, levels, 0, layers };
|
VkImageSubresourceRange range = { getImageAspect(), 0, levels, 0, layers };
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuf = commands.buffer();
|
VkCommandBuffer const cmdbuf = commands.cmdbuffer;
|
||||||
commands.acquire(this);
|
commands.acquire(this);
|
||||||
|
|
||||||
transitionLayout(cmdbuf, range, ImgUtil::getDefaultLayout(imageInfo.usage));
|
transitionLayout(cmdbuf, range, ImgUtil::getDefaultLayout(imageInfo.usage));
|
||||||
@@ -280,7 +280,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
|
|||||||
vmaFlushAllocation(mAllocator, stage->memory, 0, hostData->size);
|
vmaFlushAllocation(mAllocator, stage->memory, 0, hostData->size);
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuf = commands.buffer();
|
VkCommandBuffer const cmdbuf = commands.cmdbuffer;
|
||||||
commands.acquire(this);
|
commands.acquire(this);
|
||||||
|
|
||||||
VkBufferImageCopy copyRegion = {
|
VkBufferImageCopy copyRegion = {
|
||||||
@@ -343,7 +343,7 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u
|
|||||||
vmaFlushAllocation(mAllocator, stage->memory, 0, hostData.size);
|
vmaFlushAllocation(mAllocator, stage->memory, 0, hostData.size);
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuf = commands.buffer();
|
VkCommandBuffer const cmdbuf = commands.cmdbuffer;
|
||||||
commands.acquire(this);
|
commands.acquire(this);
|
||||||
|
|
||||||
// TODO: support blit-based format conversion for 3D images and cubemaps.
|
// TODO: support blit-based format conversion for 3D images and cubemaps.
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ void printDepthFormats(VkPhysicalDevice device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExtensionSet getInstanceExtensions() {
|
ExtensionSet getInstanceExtensions() {
|
||||||
std::string_view const TARGET_EXTS[] = {
|
std::array<std::string_view, 4> const TARGET_EXTS = {
|
||||||
// Request all cross-platform extensions.
|
// Request all cross-platform extensions.
|
||||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
|
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
|
||||||
@@ -160,10 +160,6 @@ ExtensionSet getInstanceExtensions() {
|
|||||||
// Request these if available.
|
// Request these if available.
|
||||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||||
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
|
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
|
||||||
|
|
||||||
#if VK_ENABLE_VALIDATION
|
|
||||||
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
ExtensionSet exts;
|
ExtensionSet exts;
|
||||||
FixedCapacityVector<VkExtensionProperties> const availableExts
|
FixedCapacityVector<VkExtensionProperties> const availableExts
|
||||||
@@ -180,7 +176,7 @@ ExtensionSet getInstanceExtensions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||||
std::string_view const TARGET_EXTS[] = {
|
std::array<std::string_view, 5> const TARGET_EXTS = {
|
||||||
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
||||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||||
@@ -235,10 +231,13 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
|
|
||||||
// The Platform class can require 1 or 2 instance extensions, plus we'll request at most 5
|
// The Platform class can require 1 or 2 instance extensions, plus we'll request at most 5
|
||||||
// instance extensions here in the common code. So that's a max of 7.
|
// instance extensions here in the common code. So that's a max of 7.
|
||||||
static constexpr uint32_t MAX_INSTANCE_EXTENSION_COUNT = 8;
|
static constexpr uint32_t MAX_INSTANCE_EXTENSION_COUNT = 7;
|
||||||
const char* ppEnabledExtensions[MAX_INSTANCE_EXTENSION_COUNT];
|
const char* ppEnabledExtensions[MAX_INSTANCE_EXTENSION_COUNT];
|
||||||
uint32_t enabledExtensionCount = 0;
|
uint32_t enabledExtensionCount = 0;
|
||||||
|
|
||||||
|
#if VK_ENABLE_VALIDATION && defined(__ANDROID__)
|
||||||
|
ppEnabledExtensions[enabledExtensionCount++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
|
||||||
|
#endif
|
||||||
if (validationFeaturesSupported) {
|
if (validationFeaturesSupported) {
|
||||||
ppEnabledExtensions[enabledExtensionCount++] = VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME;
|
ppEnabledExtensions[enabledExtensionCount++] = VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME;
|
||||||
}
|
}
|
||||||
@@ -513,7 +512,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
|
|||||||
|
|
||||||
VkFormat findSupportedFormat(VkPhysicalDevice device) {
|
VkFormat findSupportedFormat(VkPhysicalDevice device) {
|
||||||
VkFormatFeatureFlags const features = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
VkFormatFeatureFlags const features = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
VkFormat const formats[] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_X8_D24_UNORM_PACK32};
|
std::array<VkFormat, 2> const formats = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
for (VkFormat format: formats) {
|
for (VkFormat format: formats) {
|
||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||||
|
|||||||
@@ -211,5 +211,66 @@ int runTests() {
|
|||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getPixelInfo(PixelDataFormat format, PixelDataType type, size_t& outComponents, int& outBpp) {
|
||||||
|
assert_invariant(type != PixelDataType::COMPRESSED);
|
||||||
|
switch (format) {
|
||||||
|
case PixelDataFormat::UNUSED:
|
||||||
|
case PixelDataFormat::R:
|
||||||
|
case PixelDataFormat::R_INTEGER:
|
||||||
|
case PixelDataFormat::DEPTH_COMPONENT:
|
||||||
|
case PixelDataFormat::ALPHA:
|
||||||
|
outComponents = 1;
|
||||||
|
break;
|
||||||
|
case PixelDataFormat::RG:
|
||||||
|
case PixelDataFormat::RG_INTEGER:
|
||||||
|
case PixelDataFormat::DEPTH_STENCIL:
|
||||||
|
outComponents = 2;
|
||||||
|
break;
|
||||||
|
case PixelDataFormat::RGB:
|
||||||
|
case PixelDataFormat::RGB_INTEGER:
|
||||||
|
outComponents = 3;
|
||||||
|
break;
|
||||||
|
case PixelDataFormat::RGBA:
|
||||||
|
case PixelDataFormat::RGBA_INTEGER:
|
||||||
|
outComponents = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBpp = outComponents;
|
||||||
|
switch (type) {
|
||||||
|
case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings
|
||||||
|
case PixelDataType::UBYTE:
|
||||||
|
case PixelDataType::BYTE:
|
||||||
|
// nothing to do
|
||||||
|
break;
|
||||||
|
case PixelDataType::USHORT:
|
||||||
|
case PixelDataType::SHORT:
|
||||||
|
case PixelDataType::HALF:
|
||||||
|
outBpp *= 2;
|
||||||
|
break;
|
||||||
|
case PixelDataType::UINT:
|
||||||
|
case PixelDataType::INT:
|
||||||
|
case PixelDataType::FLOAT:
|
||||||
|
outBpp *= 4;
|
||||||
|
break;
|
||||||
|
case PixelDataType::UINT_10F_11F_11F_REV:
|
||||||
|
// Special case, format must be RGB and uses 4 bytes
|
||||||
|
assert_invariant(format == PixelDataFormat::RGB);
|
||||||
|
outBpp = 4;
|
||||||
|
break;
|
||||||
|
case PixelDataType::UINT_2_10_10_10_REV:
|
||||||
|
// Special case, format must be RGBA and uses 4 bytes
|
||||||
|
assert_invariant(format == PixelDataFormat::RGBA);
|
||||||
|
outBpp = 4;
|
||||||
|
break;
|
||||||
|
case PixelDataType::USHORT_565:
|
||||||
|
// Special case, format must be RGB and uses 2 bytes
|
||||||
|
assert_invariant(format == PixelDataFormat::RGB);
|
||||||
|
outBpp = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ private:
|
|||||||
filament::backend::Handle<filament::backend::HwBufferObject> uniform;
|
filament::backend::Handle<filament::backend::HwBufferObject> uniform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
void getPixelInfo(filament::backend::PixelDataFormat format, filament::backend::PixelDataType type,
|
||||||
|
size_t& outComponents, int& outBpp);
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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_BACKENDTESTUTILS_H
|
|
||||||
#define TNT_BACKENDTESTUTILS_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include <backend/PixelBufferDescriptor.h>
|
|
||||||
|
|
||||||
using namespace filament;
|
|
||||||
using namespace filament::backend;
|
|
||||||
|
|
||||||
inline void getPixelInfo(PixelDataFormat format, PixelDataType type, size_t& outComponents, int& outBpp) {
|
|
||||||
assert_invariant(type != PixelDataType::COMPRESSED);
|
|
||||||
switch (format) {
|
|
||||||
case PixelDataFormat::UNUSED:
|
|
||||||
case PixelDataFormat::R:
|
|
||||||
case PixelDataFormat::R_INTEGER:
|
|
||||||
case PixelDataFormat::DEPTH_COMPONENT:
|
|
||||||
case PixelDataFormat::ALPHA:
|
|
||||||
outComponents = 1;
|
|
||||||
break;
|
|
||||||
case PixelDataFormat::RG:
|
|
||||||
case PixelDataFormat::RG_INTEGER:
|
|
||||||
case PixelDataFormat::DEPTH_STENCIL:
|
|
||||||
outComponents = 2;
|
|
||||||
break;
|
|
||||||
case PixelDataFormat::RGB:
|
|
||||||
case PixelDataFormat::RGB_INTEGER:
|
|
||||||
outComponents = 3;
|
|
||||||
break;
|
|
||||||
case PixelDataFormat::RGBA:
|
|
||||||
case PixelDataFormat::RGBA_INTEGER:
|
|
||||||
outComponents = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outBpp = outComponents;
|
|
||||||
switch (type) {
|
|
||||||
case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings
|
|
||||||
case PixelDataType::UBYTE:
|
|
||||||
case PixelDataType::BYTE:
|
|
||||||
// nothing to do
|
|
||||||
break;
|
|
||||||
case PixelDataType::USHORT:
|
|
||||||
case PixelDataType::SHORT:
|
|
||||||
case PixelDataType::HALF:
|
|
||||||
outBpp *= 2;
|
|
||||||
break;
|
|
||||||
case PixelDataType::UINT:
|
|
||||||
case PixelDataType::INT:
|
|
||||||
case PixelDataType::FLOAT:
|
|
||||||
outBpp *= 4;
|
|
||||||
break;
|
|
||||||
case PixelDataType::UINT_10F_11F_11F_REV:
|
|
||||||
// Special case, format must be RGB and uses 4 bytes
|
|
||||||
assert_invariant(format == PixelDataFormat::RGB);
|
|
||||||
outBpp = 4;
|
|
||||||
break;
|
|
||||||
case PixelDataType::UINT_2_10_10_10_REV:
|
|
||||||
// Special case, format must be RGBA and uses 4 bytes
|
|
||||||
assert_invariant(format == PixelDataFormat::RGBA);
|
|
||||||
outBpp = 4;
|
|
||||||
break;
|
|
||||||
case PixelDataType::USHORT_565:
|
|
||||||
// Special case, format must be RGB and uses 2 bytes
|
|
||||||
assert_invariant(format == PixelDataFormat::RGB);
|
|
||||||
outBpp = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ComponentType>
|
|
||||||
static void fillCheckerboard(void* buffer, size_t size, size_t stride, size_t components,
|
|
||||||
ComponentType value) {
|
|
||||||
ComponentType* row = (ComponentType*)buffer;
|
|
||||||
int p = 0;
|
|
||||||
for (int r = 0; r < size; r++) {
|
|
||||||
ComponentType* pixel = row;
|
|
||||||
for (int col = 0; col < size; col++) {
|
|
||||||
// Generate a checkerboard pattern.
|
|
||||||
if ((p & 0x0010) ^ ((p / size) & 0x0010)) {
|
|
||||||
// Turn on the first component (red).
|
|
||||||
pixel[0] = value;
|
|
||||||
}
|
|
||||||
pixel += components;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
row += stride * components;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PixelBufferDescriptor checkerboardPixelBuffer(PixelDataFormat format, PixelDataType type,
|
|
||||||
size_t size, size_t bufferPadding = 0) {
|
|
||||||
size_t components; int bpp;
|
|
||||||
getPixelInfo(format, type, components, bpp);
|
|
||||||
|
|
||||||
size_t bufferSize = size + bufferPadding * 2;
|
|
||||||
uint8_t* buffer = (uint8_t*) calloc(1, bufferSize * bufferSize * bpp);
|
|
||||||
|
|
||||||
uint8_t* ptr = buffer + (bufferSize * bufferPadding * bpp) + (bufferPadding * bpp);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PixelDataType::BYTE:
|
|
||||||
fillCheckerboard<int8_t>(ptr, size, bufferSize, components, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::UBYTE:
|
|
||||||
fillCheckerboard<uint8_t>(ptr, size, bufferSize, components, 0xFF);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::SHORT:
|
|
||||||
fillCheckerboard<int16_t>(ptr, size, bufferSize, components, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::USHORT:
|
|
||||||
fillCheckerboard<uint16_t>(ptr, size, bufferSize, components, 1u);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::UINT:
|
|
||||||
fillCheckerboard<uint32_t>(ptr, size, bufferSize, components, 1u);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::INT:
|
|
||||||
fillCheckerboard<int32_t>(ptr, size, bufferSize, components, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::FLOAT:
|
|
||||||
fillCheckerboard<float>(ptr, size, bufferSize, components, 1.0f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::HALF:
|
|
||||||
fillCheckerboard<math::half>(ptr, size, bufferSize, components, math::half(1.0f));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::UINT_2_10_10_10_REV:
|
|
||||||
fillCheckerboard<uint32_t>(ptr, size, bufferSize, 1, 0xC00003FF /* red */);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::USHORT_565:
|
|
||||||
fillCheckerboard<uint16_t>(ptr, size, bufferSize, 1, 0xF800 /* red */);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::UINT_10F_11F_11F_REV:
|
|
||||||
fillCheckerboard<uint32_t>(ptr, size, bufferSize, 1, 0x000003C0 /* red */);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelDataType::COMPRESSED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelBufferDescriptor descriptor(buffer, bufferSize * bufferSize * bpp, format, type,
|
|
||||||
1, bufferPadding, bufferPadding, bufferSize, [](void* buffer, size_t size, void* user) {
|
|
||||||
free(buffer);
|
|
||||||
}, nullptr);
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // TNT_BACKENDTESTUTILS_H
|
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include "ShaderGenerator.h"
|
#include "ShaderGenerator.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
#include "BackendTestUtils.h"
|
|
||||||
|
|
||||||
#include "private/filament/SamplerInterfaceBlock.h"
|
#include "private/filament/SamplerInterfaceBlock.h"
|
||||||
#include "private/backend/SamplerGroup.h"
|
#include "private/backend/SamplerGroup.h"
|
||||||
@@ -114,7 +113,91 @@ namespace test {
|
|||||||
|
|
||||||
template<typename componentType> inline componentType getMaxValue();
|
template<typename componentType> inline componentType getMaxValue();
|
||||||
|
|
||||||
|
template<typename ComponentType>
|
||||||
|
static void fillCheckerboard(void* buffer, size_t size, size_t stride, size_t components,
|
||||||
|
ComponentType value) {
|
||||||
|
ComponentType* row = (ComponentType*)buffer;
|
||||||
|
int p = 0;
|
||||||
|
for (int r = 0; r < size; r++) {
|
||||||
|
ComponentType* pixel = row;
|
||||||
|
for (int col = 0; col < size; col++) {
|
||||||
|
// Generate a checkerboard pattern.
|
||||||
|
if ((p & 0x0010) ^ ((p / size) & 0x0010)) {
|
||||||
|
// Turn on the first component (red).
|
||||||
|
pixel[0] = value;
|
||||||
|
}
|
||||||
|
pixel += components;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
row += stride * components;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PixelBufferDescriptor checkerboardPixelBuffer(PixelDataFormat format, PixelDataType type,
|
||||||
|
size_t size, size_t bufferPadding = 0) {
|
||||||
|
size_t components; int bpp;
|
||||||
|
getPixelInfo(format, type, components, bpp);
|
||||||
|
|
||||||
|
size_t bufferSize = size + bufferPadding * 2;
|
||||||
|
uint8_t* buffer = (uint8_t*) calloc(1, bufferSize * bufferSize * bpp);
|
||||||
|
|
||||||
|
uint8_t* ptr = buffer + (bufferSize * bufferPadding * bpp) + (bufferPadding * bpp);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PixelDataType::BYTE:
|
||||||
|
fillCheckerboard<int8_t>(ptr, size, bufferSize, components, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::UBYTE:
|
||||||
|
fillCheckerboard<uint8_t>(ptr, size, bufferSize, components, 0xFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::SHORT:
|
||||||
|
fillCheckerboard<int16_t>(ptr, size, bufferSize, components, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::USHORT:
|
||||||
|
fillCheckerboard<uint16_t>(ptr, size, bufferSize, components, 1u);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::UINT:
|
||||||
|
fillCheckerboard<uint32_t>(ptr, size, bufferSize, components, 1u);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::INT:
|
||||||
|
fillCheckerboard<int32_t>(ptr, size, bufferSize, components, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::FLOAT:
|
||||||
|
fillCheckerboard<float>(ptr, size, bufferSize, components, 1.0f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::HALF:
|
||||||
|
fillCheckerboard<math::half>(ptr, size, bufferSize, components, math::half(1.0f));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::UINT_2_10_10_10_REV:
|
||||||
|
fillCheckerboard<uint32_t>(ptr, size, bufferSize, 1, 0xC00003FF /* red */);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::USHORT_565:
|
||||||
|
fillCheckerboard<uint16_t>(ptr, size, bufferSize, 1, 0xF800 /* red */);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::UINT_10F_11F_11F_REV:
|
||||||
|
fillCheckerboard<uint32_t>(ptr, size, bufferSize, 1, 0x000003C0 /* red */);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelDataType::COMPRESSED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelBufferDescriptor descriptor(buffer, bufferSize * bufferSize * bpp, format, type,
|
||||||
|
1, bufferPadding, bufferPadding, bufferSize, [](void* buffer, size_t size, void* user) {
|
||||||
|
free(buffer);
|
||||||
|
}, nullptr);
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string stringReplace(const std::string& find, const std::string& replace,
|
inline std::string stringReplace(const std::string& find, const std::string& replace,
|
||||||
std::string source) {
|
std::string source) {
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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 "BackendTest.h"
|
|
||||||
|
|
||||||
#include "ShaderGenerator.h"
|
|
||||||
#include "TrianglePrimitive.h"
|
|
||||||
#include "BackendTestUtils.h"
|
|
||||||
|
|
||||||
#include "private/backend/SamplerGroup.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Shaders
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::string vertex (R"(#version 450 core
|
|
||||||
|
|
||||||
layout(location = 0) in vec4 mesh_position;
|
|
||||||
layout(location = 0) out vec2 uv;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = vec4(mesh_position.xy, 0.0, 1.0);
|
|
||||||
uv = (mesh_position.xy * 0.5 + 0.5);
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
|
|
||||||
std::string fragment (R"(#version 450 core
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
layout(location = 0) in vec2 uv;
|
|
||||||
|
|
||||||
layout(location = 0, set = 1) uniform sampler2D backend_test_sib_tex;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
fragColor = textureLod(backend_test_sib_tex, uv, 1);
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
using namespace filament;
|
|
||||||
using namespace filament::backend;
|
|
||||||
|
|
||||||
TEST_F(BackendTest, SetMinMaxLevel) {
|
|
||||||
auto& api = getDriverApi();
|
|
||||||
api.startCapture(0);
|
|
||||||
|
|
||||||
// The test is executed within this block scope to force destructors to run before
|
|
||||||
// executeCommands().
|
|
||||||
{
|
|
||||||
// Create a SwapChain and make it current.
|
|
||||||
auto swapChain = createSwapChain();
|
|
||||||
api.makeCurrent(swapChain, swapChain);
|
|
||||||
|
|
||||||
// Create a program that samples a texture.
|
|
||||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
|
||||||
.name("backend_test_sib")
|
|
||||||
.stageFlags(backend::ShaderStageFlags::FRAGMENT)
|
|
||||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
|
||||||
.build();
|
|
||||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
|
||||||
Program p = shaderGen.getProgram(api);
|
|
||||||
Program::Sampler sampler { utils::CString("backend_test_sib_tex"), 0 };
|
|
||||||
p.setSamplerGroup(0, ShaderStageFlags::FRAGMENT, &sampler, 1);
|
|
||||||
auto program = api.createProgram(std::move(p));
|
|
||||||
|
|
||||||
// Create a texture that has 4 mip levels. Each level is a different color.
|
|
||||||
// Level 0: 128x128 (red)
|
|
||||||
// Level 1: 64x64 (green)
|
|
||||||
// Level 2: 32x32 (blue)
|
|
||||||
// Level 3: 16x16 (yellow)
|
|
||||||
const size_t kTextureSize = 128;
|
|
||||||
const size_t kMipLevels = 4;
|
|
||||||
Handle<HwTexture> texture = api.createTexture(SamplerType::SAMPLER_2D, kMipLevels,
|
|
||||||
TextureFormat::RGBA8, 1, kTextureSize, kTextureSize, 1,
|
|
||||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE);
|
|
||||||
|
|
||||||
// Create image data.
|
|
||||||
auto pixelFormat = PixelDataFormat::RGBA;
|
|
||||||
auto pixelType = PixelDataType::UBYTE;
|
|
||||||
size_t components; int bpp;
|
|
||||||
getPixelInfo(pixelFormat, pixelType, components, bpp);
|
|
||||||
uint32_t colors[] = {
|
|
||||||
0xFF0000FF, /* red */
|
|
||||||
0xFF00FF00, /* green */
|
|
||||||
0xFFFF0000, /* blue */
|
|
||||||
0xFF00FFFF, /* yellow */
|
|
||||||
};
|
|
||||||
for (int l = 0; l < kMipLevels; l++) {
|
|
||||||
size_t mipSize = kTextureSize >> l;
|
|
||||||
auto* buffer = (uint8_t*)calloc(1, mipSize * mipSize * bpp);
|
|
||||||
fillCheckerboard<uint32_t>(buffer, mipSize, mipSize, 1, colors[l]);
|
|
||||||
PixelBufferDescriptor descriptor(
|
|
||||||
buffer, mipSize * mipSize * bpp, pixelFormat, pixelType, 1, 0, 0,
|
|
||||||
mipSize, [](void* buffer, size_t size, void* user) { free(buffer); },
|
|
||||||
nullptr);
|
|
||||||
api.update3DImage(
|
|
||||||
texture, l, 0, 0, 0, mipSize, mipSize, 1, std::move(descriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
api.setMinMaxLevels(texture, 1, 3);
|
|
||||||
|
|
||||||
backend::Handle<HwRenderTarget> defaultRenderTarget = api.createDefaultRenderTarget(0);
|
|
||||||
|
|
||||||
RenderPassParams params = {};
|
|
||||||
fullViewport(params);
|
|
||||||
params.flags.clear = TargetBufferFlags::COLOR;
|
|
||||||
params.clearColor = {0.f, 0.f, 0.5f, 1.f};
|
|
||||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
|
||||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
|
||||||
|
|
||||||
PipelineState state;
|
|
||||||
state.scissor = params.viewport;
|
|
||||||
state.program = program;
|
|
||||||
state.rasterState.colorWrite = true;
|
|
||||||
state.rasterState.depthWrite = false;
|
|
||||||
state.rasterState.depthFunc = SamplerCompareFunc::A;
|
|
||||||
state.rasterState.culling = CullingMode::NONE;
|
|
||||||
|
|
||||||
api.beginFrame(0, 0);
|
|
||||||
|
|
||||||
SamplerGroup samplers(1);
|
|
||||||
SamplerParams samplerParams {};
|
|
||||||
samplerParams.filterMag = SamplerMagFilter::NEAREST;
|
|
||||||
samplerParams.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST;
|
|
||||||
samplers.setSampler(0, { texture, samplerParams });
|
|
||||||
backend::Handle<HwSamplerGroup> samplerGroup = api.createSamplerGroup(1);
|
|
||||||
api.updateSamplerGroup(samplerGroup, samplers.toBufferDescriptor(api));
|
|
||||||
api.bindSamplers(0, samplerGroup);
|
|
||||||
|
|
||||||
// Render a triangle to the screen, sampling from mip level 1.
|
|
||||||
// Because the min level is 1, the result color should be blue.
|
|
||||||
TrianglePrimitive triangle(api);
|
|
||||||
api.beginRenderPass(defaultRenderTarget, params);
|
|
||||||
api.draw(state, triangle.getRenderPrimitive(), 1);
|
|
||||||
api.endRenderPass();
|
|
||||||
|
|
||||||
api.commit(swapChain);
|
|
||||||
api.endFrame(0);
|
|
||||||
|
|
||||||
api.stopCapture(0);
|
|
||||||
|
|
||||||
// Cleanup.
|
|
||||||
api.destroySwapChain(swapChain);
|
|
||||||
}
|
|
||||||
|
|
||||||
api.finish();
|
|
||||||
|
|
||||||
executeCommands();
|
|
||||||
getDriver().purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test
|
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include "ShaderGenerator.h"
|
#include "ShaderGenerator.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
#include "BackendTestUtils.h"
|
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <utils/EntityInstance.h>
|
#include <utils/EntityInstance.h>
|
||||||
|
|
||||||
#include <math/mathfwd.h>
|
#include <math/mathfwd.h>
|
||||||
#include <math/quat.h>
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
class Entity;
|
class Entity;
|
||||||
@@ -245,7 +244,6 @@ public:
|
|||||||
* shadows that are too far and wouldn't contribute to the scene much, improving
|
* shadows that are too far and wouldn't contribute to the scene much, improving
|
||||||
* performance and quality. This value is always positive.
|
* performance and quality. This value is always positive.
|
||||||
* Use 0.0f to use the camera far distance.
|
* Use 0.0f to use the camera far distance.
|
||||||
* This only affect directional lights.
|
|
||||||
*/
|
*/
|
||||||
float shadowFar = 0.0f;
|
float shadowFar = 0.0f;
|
||||||
|
|
||||||
@@ -362,13 +360,6 @@ public:
|
|||||||
* enabled. (2cm by default).
|
* enabled. (2cm by default).
|
||||||
*/
|
*/
|
||||||
float shadowBulbRadius = 0.02f;
|
float shadowBulbRadius = 0.02f;
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms the shadow direction. Must be a unit quaternion.
|
|
||||||
* The default is identity.
|
|
||||||
* Ignored if the light type isn't directional. For artistic use. Use with caution.
|
|
||||||
*/
|
|
||||||
math::quatf transform{ 1.0f };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShadowCascades {
|
struct ShadowCascades {
|
||||||
@@ -680,7 +671,7 @@ public:
|
|||||||
* @return true is this light is a type of directional light
|
* @return true is this light is a type of directional light
|
||||||
*/
|
*/
|
||||||
inline bool isDirectional(Instance i) const noexcept {
|
inline bool isDirectional(Instance i) const noexcept {
|
||||||
Type const type = getType(i);
|
Type type = getType(i);
|
||||||
return type == Type::DIRECTIONAL || type == Type::SUN;
|
return type == Type::DIRECTIONAL || type == Type::SUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +692,7 @@ public:
|
|||||||
* @return true is this light is a type of spot light
|
* @return true is this light is a type of spot light
|
||||||
*/
|
*/
|
||||||
inline bool isSpotLight(Instance i) const noexcept {
|
inline bool isSpotLight(Instance i) const noexcept {
|
||||||
Type const type = getType(i);
|
Type type = getType(i);
|
||||||
return type == Type::SPOT || type == Type::FOCUSED_SPOT;
|
return type == Type::SPOT || type == Type::FOCUSED_SPOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ void PerViewUniforms::prepareDirectionalLight(FEngine& engine,
|
|||||||
float exposure,
|
float exposure,
|
||||||
float3 const& sceneSpaceDirection,
|
float3 const& sceneSpaceDirection,
|
||||||
PerViewUniforms::LightManagerInstance directionalLight) noexcept {
|
PerViewUniforms::LightManagerInstance directionalLight) noexcept {
|
||||||
FLightManager const& lcm = engine.getLightManager();
|
FLightManager& lcm = engine.getLightManager();
|
||||||
auto& s = mUniforms.edit();
|
auto& s = mUniforms.edit();
|
||||||
|
|
||||||
const float3 l = -sceneSpaceDirection; // guaranteed normalized
|
const float3 l = -sceneSpaceDirection; // guaranteed normalized
|
||||||
@@ -302,11 +302,11 @@ void PerViewUniforms::prepareDirectionalLight(FEngine& engine,
|
|||||||
// The last parameter must be < 0.0f for regular directional lights
|
// The last parameter must be < 0.0f for regular directional lights
|
||||||
float4 sun{ 0.0f, 0.0f, 0.0f, -1.0f };
|
float4 sun{ 0.0f, 0.0f, 0.0f, -1.0f };
|
||||||
if (UTILS_UNLIKELY(isSun && colorIntensity.w > 0.0f)) {
|
if (UTILS_UNLIKELY(isSun && colorIntensity.w > 0.0f)) {
|
||||||
// Currently we have only a single directional light, so it's probably likely that it's
|
// currently we have only a single directional light, so it's probably likely that it's
|
||||||
// also the Sun. However, conceptually, most directional lights won't be sun lights.
|
// also the Sun. However, conceptually, most directional lights won't be sun lights.
|
||||||
float const radius = lcm.getSunAngularRadius(directionalLight);
|
float radius = lcm.getSunAngularRadius(directionalLight);
|
||||||
float const haloSize = lcm.getSunHaloSize(directionalLight);
|
float haloSize = lcm.getSunHaloSize(directionalLight);
|
||||||
float const haloFalloff = lcm.getSunHaloFalloff(directionalLight);
|
float haloFalloff = lcm.getSunHaloFalloff(directionalLight);
|
||||||
sun.x = std::cos(radius);
|
sun.x = std::cos(radius);
|
||||||
sun.y = std::sin(radius);
|
sun.y = std::sin(radius);
|
||||||
sun.z = 1.0f / (std::cos(radius * haloSize) - sun.x);
|
sun.z = 1.0f / (std::cos(radius * haloSize) - sun.x);
|
||||||
|
|||||||
+75
-126
@@ -110,7 +110,7 @@ math::mat4f ShadowMap::getPointLightViewMatrix(backend::TextureCubemapFace face,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||||
FScene::LightSoa const& lightData, size_t index,
|
const FScene::LightSoa& lightData, size_t index,
|
||||||
filament::CameraInfo const& camera,
|
filament::CameraInfo const& camera,
|
||||||
ShadowMapInfo const& shadowMapInfo,
|
ShadowMapInfo const& shadowMapInfo,
|
||||||
SceneInfo const& sceneInfo) noexcept {
|
SceneInfo const& sceneInfo) noexcept {
|
||||||
@@ -131,7 +131,20 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
else params.options.shadowFarHint = dzf * dz + camera.zf;
|
else params.options.shadowFarHint = dzf * dz + camera.zf;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto direction = params.options.transform * lightData.elementAt<FScene::DIRECTION>(index);
|
// Adjust the camera's projection for the light's shadowFar
|
||||||
|
const mat4f cullingProjection{ [&](auto p) {
|
||||||
|
if (params.options.shadowFar > 0.0f) {
|
||||||
|
float const n = camera.zn;
|
||||||
|
float const f = params.options.shadowFar;
|
||||||
|
// orthographic projection
|
||||||
|
assert_invariant(std::abs(p[2].w) <= std::numeric_limits<float>::epsilon());
|
||||||
|
p[2].z = 2.0f / (n - f);
|
||||||
|
p[3].z = (f + n) / (n - f);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}(camera.cullingProjection) };
|
||||||
|
|
||||||
|
const auto direction = lightData.elementAt<FScene::DIRECTION>(index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the light's model matrix
|
* Compute the light's model matrix
|
||||||
@@ -151,7 +164,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
|
|
||||||
// view frustum vertices in world-space
|
// view frustum vertices in world-space
|
||||||
float3 wsViewFrustumVertices[8];
|
float3 wsViewFrustumVertices[8];
|
||||||
const mat4f worldToClipMatrix = camera.cullingProjection * camera.view;
|
const mat4f worldToClipMatrix = cullingProjection * camera.view;
|
||||||
const Frustum wsFrustum(worldToClipMatrix);
|
const Frustum wsFrustum(worldToClipMatrix);
|
||||||
computeFrustumCorners(wsViewFrustumVertices, inverse(worldToClipMatrix), sceneInfo.csNearFar);
|
computeFrustumCorners(wsViewFrustumVertices, inverse(worldToClipMatrix), sceneInfo.csNearFar);
|
||||||
|
|
||||||
@@ -203,7 +216,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now that we know the znear (-lsLightFrustumBounds.max.z), adjust the light's position such
|
// Now that we know the znear (-lsLightFrustumBounds.max.z), adjust the light's position such
|
||||||
// that znear = 0, this is only needed for VSM, but doesn't hurt PCF.
|
// that znear = 0, this is only need for VSM, but doesn't hurt PCF.
|
||||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, direction * -lsLightFrustumBounds.max.z);
|
const mat4f Mv = getDirectionalLightViewMatrix(direction, direction * -lsLightFrustumBounds.max.z);
|
||||||
|
|
||||||
// near / far planes are specified relative to the direction the eye is looking at
|
// near / far planes are specified relative to the direction the eye is looking at
|
||||||
@@ -227,11 +240,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
const float4 shadowReceiverVolumeBoundingSphere = computeBoundingSphere(
|
const float4 shadowReceiverVolumeBoundingSphere = computeBoundingSphere(
|
||||||
wsShadowReceiversVolume.getCorners().data(), 8);
|
wsShadowReceiversVolume.getCorners().data(), 8);
|
||||||
|
|
||||||
// in stable mode we simply take the view volume bounding sphere, but we calculate it
|
// in stable mode we simply take the view volume, bounding sphere
|
||||||
// in view space, so that it's perfectly stable.
|
viewVolumeBoundingSphere = computeBoundingSphere(wsViewFrustumVertices, 8);
|
||||||
float3 vertices[8];
|
|
||||||
computeFrustumCorners(vertices, inverse(camera.cullingProjection), sceneInfo.csNearFar);
|
|
||||||
viewVolumeBoundingSphere = computeBoundingSphere(vertices, 8);
|
|
||||||
|
|
||||||
if (shadowReceiverVolumeBoundingSphere.w < viewVolumeBoundingSphere.w) {
|
if (shadowReceiverVolumeBoundingSphere.w < viewVolumeBoundingSphere.w) {
|
||||||
|
|
||||||
@@ -310,65 +320,45 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
//
|
//
|
||||||
// In LiPSM mode, we're using the warped space here.
|
// In LiPSM mode, we're using the warped space here.
|
||||||
|
|
||||||
float2 s, o;
|
Aabb bounds;
|
||||||
|
if (params.options.stable && viewVolumeBoundingSphere.w > 0) {
|
||||||
|
bounds = compute2DBounds(Mv, viewVolumeBoundingSphere);
|
||||||
|
} else {
|
||||||
|
bounds = compute2DBounds(WLMpMv, wsClippedShadowReceiverVolume.data(), vertexCount);
|
||||||
|
}
|
||||||
|
lsLightFrustumBounds.min.xy = bounds.min.xy;
|
||||||
|
lsLightFrustumBounds.max.xy = bounds.max.xy;
|
||||||
|
|
||||||
if (params.options.stable) {
|
if (params.options.stable) {
|
||||||
if (viewVolumeBoundingSphere.w > 0) {
|
// in stable mode we can't do anything that can change the scaling of the texture
|
||||||
s = 1.0f / viewVolumeBoundingSphere.w;
|
|
||||||
o = mat4f::project(LMpMv * camera.model, viewVolumeBoundingSphere.xyz).xy;
|
|
||||||
} else {
|
|
||||||
Aabb const bounds = compute2DBounds(LMpMv,
|
|
||||||
wsClippedShadowReceiverVolume.data(), vertexCount);
|
|
||||||
if (UTILS_UNLIKELY((bounds.min.x >= bounds.max.x) || (bounds.min.y >= bounds.max.y))) {
|
|
||||||
// this could happen if the only thing visible is a perfectly horizontal or
|
|
||||||
// vertical thin line
|
|
||||||
mHasVisibleShadows = false;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
assert_invariant(bounds.min.x < bounds.max.x);
|
|
||||||
assert_invariant(bounds.min.y < bounds.max.y);
|
|
||||||
|
|
||||||
s = 2.0f / float2(bounds.max.xy - bounds.min.xy);
|
|
||||||
o = float2(bounds.max.xy + bounds.min.xy) * 0.5f;
|
|
||||||
|
|
||||||
// Quantize the scale in world-space units. This value can be very small because
|
|
||||||
// if it wasn't for floating-point imprecision, the scale would be a constant.
|
|
||||||
double2 const quantizer = 0.0625;
|
|
||||||
s = 1.0 / (ceil(1.0 / (s * quantizer)) * quantizer);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Aabb const bounds = compute2DBounds(WLMpMv,
|
|
||||||
wsClippedShadowReceiverVolume.data(), vertexCount);
|
|
||||||
lsLightFrustumBounds.min.xy = bounds.min.xy;
|
|
||||||
lsLightFrustumBounds.max.xy = bounds.max.xy;
|
|
||||||
// For directional lights, we further constraint the light frustum to the
|
// For directional lights, we further constraint the light frustum to the
|
||||||
// intersection of the shadow casters & shadow receivers in light-space.
|
// intersection of the shadow casters & shadow receivers in light-space.
|
||||||
// ** This relies on the 1-texel shadow map border **
|
// ** This relies on the 1-texel shadow map border **
|
||||||
if (engine.debug.shadowmap.focus_shadowcasters) {
|
if (engine.debug.shadowmap.focus_shadowcasters) {
|
||||||
intersectWithShadowCasters(lsLightFrustumBounds, WLMpMv, wsShadowCastersVolume);
|
intersectWithShadowCasters(lsLightFrustumBounds, WLMpMv, wsShadowCastersVolume);
|
||||||
}
|
}
|
||||||
if (UTILS_UNLIKELY((lsLightFrustumBounds.min.x >= lsLightFrustumBounds.max.x) ||
|
|
||||||
(lsLightFrustumBounds.min.y >= lsLightFrustumBounds.max.y))) {
|
|
||||||
// this could happen if the only thing visible is a perfectly horizontal or
|
|
||||||
// vertical thin line
|
|
||||||
mHasVisibleShadows = false;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
assert_invariant(lsLightFrustumBounds.min.x < lsLightFrustumBounds.max.x);
|
|
||||||
assert_invariant(lsLightFrustumBounds.min.y < lsLightFrustumBounds.max.y);
|
|
||||||
|
|
||||||
s = 2.0f / float2(bounds.max.xy - bounds.min.xy);
|
|
||||||
o = float2(bounds.max.xy + bounds.min.xy) * 0.5f;
|
|
||||||
|
|
||||||
// TODO: we could quantize `s` here to give some stability when lispsm is disabled,
|
|
||||||
// however, the quantization paramater should probably be user settable.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust offset for scale
|
if (UTILS_UNLIKELY((lsLightFrustumBounds.min.x >= lsLightFrustumBounds.max.x) ||
|
||||||
o = -s * o;
|
(lsLightFrustumBounds.min.y >= lsLightFrustumBounds.max.y))) {
|
||||||
|
// this could happen if the only thing visible is a perfectly horizontal or
|
||||||
|
// vertical thin line
|
||||||
|
mHasVisibleShadows = false;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_invariant(lsLightFrustumBounds.min.x < lsLightFrustumBounds.max.x);
|
||||||
|
assert_invariant(lsLightFrustumBounds.min.y < lsLightFrustumBounds.max.y);
|
||||||
|
|
||||||
|
// compute focus scale and offset
|
||||||
|
float2 s = 2.0f / float2(lsLightFrustumBounds.max.xy - lsLightFrustumBounds.min.xy);
|
||||||
|
float2 o = -s * float2(lsLightFrustumBounds.max.xy + lsLightFrustumBounds.min.xy) * 0.5f;
|
||||||
|
|
||||||
if (params.options.stable) {
|
if (params.options.stable) {
|
||||||
snapLightFrustum(s, o, LMpMv,
|
// Use the world origin as reference point, fixed w.r.t. the camera
|
||||||
sceneInfo.wsShadowCastersVolume.center(), shadowMapInfo.shadowDimension);
|
snapLightFrustum(s, o, Mv, camera.worldOrigin[3].xyz,
|
||||||
|
1.0f / float(shadowMapInfo.shadowDimension));
|
||||||
}
|
}
|
||||||
|
|
||||||
const mat4f F(mat4f::row_major_init {
|
const mat4f F(mat4f::row_major_init {
|
||||||
@@ -387,7 +377,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
|
|
||||||
// Computes St the transform to use in the shader to access the shadow map texture
|
// Computes St the transform to use in the shader to access the shadow map texture
|
||||||
// i.e. it transforms a world-space vertex to a texture coordinate in the shadowmap
|
// i.e. it transforms a world-space vertex to a texture coordinate in the shadowmap
|
||||||
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, getViewport());
|
const backend::Viewport viewport = getViewport();
|
||||||
|
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
|
||||||
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
||||||
|
|
||||||
ShadowMap::ShaderParameters shaderParameters;
|
ShadowMap::ShaderParameters shaderParameters;
|
||||||
@@ -409,7 +400,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
|||||||
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, znear, zfar);
|
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, znear, zfar);
|
||||||
}
|
}
|
||||||
|
|
||||||
shaderParameters.scissorNormalized = getClampToEdgeCoords(shadowMapInfo);
|
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
|
||||||
|
|
||||||
// We apply the constant bias in world space (as opposed to light-space) to account
|
// We apply the constant bias in world space (as opposed to light-space) to account
|
||||||
// for perspective and lispsm shadow maps. This also allows us to do this at zero-cost
|
// for perspective and lispsm shadow maps. This also allows us to do this at zero-cost
|
||||||
@@ -442,8 +433,9 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
|||||||
assert_invariant(shadowMapInfo.textureDimension == mOptions->mapSize);
|
assert_invariant(shadowMapInfo.textureDimension == mOptions->mapSize);
|
||||||
|
|
||||||
// Final shadow transform
|
// Final shadow transform
|
||||||
|
const backend::Viewport viewport = getViewport();
|
||||||
const mat4f S = math::highPrecisionMultiply(Mp, Mv);
|
const mat4f S = math::highPrecisionMultiply(Mp, Mv);
|
||||||
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, getViewport());
|
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
|
||||||
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
||||||
|
|
||||||
// TODO: focus projection
|
// TODO: focus projection
|
||||||
@@ -470,7 +462,7 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
|||||||
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, nearPlane, farPlane);
|
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, nearPlane, farPlane);
|
||||||
}
|
}
|
||||||
|
|
||||||
shaderParameters.scissorNormalized = getClampToEdgeCoords(shadowMapInfo);
|
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
|
||||||
|
|
||||||
const float3 direction = -transpose(Mv)[2].xyz;
|
const float3 direction = -transpose(Mv)[2].xyz;
|
||||||
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
||||||
@@ -833,39 +825,21 @@ void ShadowMap::computeFrustumCorners(float3* UTILS_RESTRICT out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ShadowMap::snapLightFrustum(float2& s, float2& o,
|
void ShadowMap::snapLightFrustum(float2& s, float2& o,
|
||||||
mat4f const& Mv, double3 wsSnapCoords, int2 resolution) noexcept {
|
mat4f const& Mv, float3 worldOrigin, float2 shadowMapResolution) noexcept {
|
||||||
|
|
||||||
auto proj = [](mat4 m, double3 v) -> double3 {
|
auto fmod = [](float2 x, float2 y) -> float2 {
|
||||||
// for directional light p.w == 1, exactly
|
auto mod = [](float x, float y) -> float { return std::fmod(x, y); };
|
||||||
auto p = m * v;
|
return float2{ mod(x[0], y[0]), mod(x[1], y[1]) };
|
||||||
assert_invariant(p.w == 1.0);
|
|
||||||
return p.xyz;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fract = [](auto v) {
|
// This snaps the shadow map bounds to texels.
|
||||||
using namespace std;
|
// The 2.0 comes from Mv having a NDC in the range -1,1 (so a range of 2).
|
||||||
using T = decltype(v);
|
const float2 r = 2.0f * shadowMapResolution;
|
||||||
return fmod(v, T{1});
|
o -= fmod(o, r);
|
||||||
};
|
|
||||||
|
|
||||||
const mat4 F(mat4::row_major_init {
|
|
||||||
s.x, 0.0, 0.0, o.x,
|
|
||||||
0.0, s.y, 0.0, o.y,
|
|
||||||
0.0, 0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 0.0, 1.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// The (resolution * 0.5) comes from Mv having a NDC in the range -1,1 (so a range of 2).
|
|
||||||
|
|
||||||
// focused light-space
|
|
||||||
mat4 const FMv{ F * Mv };
|
|
||||||
|
|
||||||
// This offsets the texture coordinates, so it has a fixed offset w.r.t the world
|
// This offsets the texture coordinates, so it has a fixed offset w.r.t the world
|
||||||
double2 const lsOrigin = proj(FMv, wsSnapCoords).xy;
|
const float2 lsOrigin = mat4f::project(Mv, worldOrigin).xy * s;
|
||||||
double2 const d = (fract(lsOrigin * resolution * 0.5) * 2.0) / resolution;
|
o -= fmod(lsOrigin, r);
|
||||||
|
|
||||||
// adjust offset
|
|
||||||
o -= d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ShadowMap::intersectFrustumWithBox(
|
size_t ShadowMap::intersectFrustumWithBox(
|
||||||
@@ -1068,7 +1042,7 @@ bool ShadowMap::intersectSegmentWithPlanarQuad(float3& UTILS_RESTRICT p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
float ShadowMap::texelSizeWorldSpace(const mat3f& worldToShadowTexture,
|
float ShadowMap::texelSizeWorldSpace(const mat3f& worldToShadowTexture,
|
||||||
uint16_t shadowDimension) noexcept {
|
uint16_t shadowDimension) const noexcept {
|
||||||
// The Jacobian of the transformation from texture-to-world is the matrix itself for
|
// The Jacobian of the transformation from texture-to-world is the matrix itself for
|
||||||
// orthographic projections. We just need to inverse worldToShadowTexture,
|
// orthographic projections. We just need to inverse worldToShadowTexture,
|
||||||
// which is guaranteed to be orthographic.
|
// which is guaranteed to be orthographic.
|
||||||
@@ -1083,7 +1057,7 @@ float ShadowMap::texelSizeWorldSpace(const mat3f& worldToShadowTexture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
float ShadowMap::texelSizeWorldSpace(const mat4f& Wp, const mat4f& MbMtF,
|
float ShadowMap::texelSizeWorldSpace(const mat4f& Wp, const mat4f& MbMtF,
|
||||||
uint16_t shadowDimension) noexcept {
|
uint16_t shadowDimension) const noexcept {
|
||||||
// Here we compute the Jacobian of inverse(MbMtF * Wp).
|
// Here we compute the Jacobian of inverse(MbMtF * Wp).
|
||||||
// The expression below has been computed with Mathematica. However, it's not very hard,
|
// The expression below has been computed with Mathematica. However, it's not very hard,
|
||||||
// albeit error-prone, to do it by hand because MbMtF is a linear transform.
|
// albeit error-prone, to do it by hand because MbMtF is a linear transform.
|
||||||
@@ -1104,7 +1078,7 @@ float ShadowMap::texelSizeWorldSpace(const mat4f& Wp, const mat4f& MbMtF,
|
|||||||
|
|
||||||
constexpr bool JACOBIAN_ESTIMATE = false;
|
constexpr bool JACOBIAN_ESTIMATE = false;
|
||||||
if constexpr (JACOBIAN_ESTIMATE) {
|
if constexpr (JACOBIAN_ESTIMATE) {
|
||||||
// This estimates the Jacobian -- this is a lot heavier. This is mostly for reference
|
// this estimates the Jacobian -- this is a lot heavier. This is mostly for reference
|
||||||
// and testing.
|
// and testing.
|
||||||
const mat4f Si(inverse(MbMtF * Wp));
|
const mat4f Si(inverse(MbMtF * Wp));
|
||||||
const float3 p0 = mat4f::project(Si, p);
|
const float3 p0 = mat4f::project(Si, p);
|
||||||
@@ -1243,58 +1217,33 @@ void ShadowMap::updateSceneInfoSpot(mat4f const& Mv, FScene const& scene,
|
|||||||
}
|
}
|
||||||
|
|
||||||
backend::Viewport ShadowMap::getViewport() const noexcept {
|
backend::Viewport ShadowMap::getViewport() const noexcept {
|
||||||
// We set a viewport with a 1-texel border for when we index outside the texture.
|
// We set a viewport with a 1-texel border for when we index outside the
|
||||||
// This happens only for directional lights when "focus shadow casters" is used,
|
// texture. This can only happen for the directional light when "focus shadow casters is used".
|
||||||
// or when shadowFar is smaller than the camera far.
|
|
||||||
// For spot- and point-lights we also use a 1-texel border, so that bilinear filtering
|
|
||||||
// can work properly if the shadowmap is in an atlas (and we can't rely on h/w clamp).
|
|
||||||
const uint32_t dim = mOptions->mapSize;
|
const uint32_t dim = mOptions->mapSize;
|
||||||
const uint16_t border = 1u;
|
const uint16_t border = 1u;
|
||||||
return { border, border, dim - 2u * border, dim - 2u * border };
|
return { border, border, dim - 2u * border, dim - 2u * border };
|
||||||
}
|
}
|
||||||
|
|
||||||
backend::Viewport ShadowMap::getScissor() const noexcept {
|
backend::Viewport ShadowMap::getScissor() const noexcept {
|
||||||
// We set a viewport with a 1-texel border for when we index outside the texture.
|
// We set a viewport with a 1-texel border for when we index outside the
|
||||||
// This happens only for directional lights when "focus shadow casters" is used,
|
// texture. This can only happen for the directional light when "focus shadow casters is used".
|
||||||
// or when shadowFar is smaller than the camera far.
|
|
||||||
// For spot- and point-lights we also use a 1-texel border, so that bilinear filtering
|
|
||||||
// can work properly if the shadowmap is in an atlas (and we can't rely on h/w clamp), so we
|
|
||||||
// don't scissor the border, so it gets filled with correct neighboring texels.
|
|
||||||
const uint32_t dim = mOptions->mapSize;
|
const uint32_t dim = mOptions->mapSize;
|
||||||
const uint16_t border = 1u;
|
const uint16_t border = 1u;
|
||||||
|
|
||||||
switch (mShadowType) {
|
switch (mShadowType) {
|
||||||
case ShadowType::DIRECTIONAL:
|
case ShadowType::DIRECTIONAL:
|
||||||
return { border, border, dim - 2u * border, dim - 2u * border };
|
return { border, border, dim - 2u * border, dim - 2u * border };
|
||||||
case ShadowType::SPOT:
|
case ShadowType::SPOT:
|
||||||
case ShadowType::POINT:
|
case ShadowType::POINT:
|
||||||
|
default:
|
||||||
return { 0, 0, dim, dim };
|
return { 0, 0, dim, dim };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
math::float4 ShadowMap::getClampToEdgeCoords(ShadowMapInfo const& shadowMapInfo) const noexcept {
|
math::float4 ShadowMap::getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept {
|
||||||
float border; // shadowmap border in texels
|
const auto [l, b, w, h] = getViewport();
|
||||||
switch (mShadowType) {
|
const float texel = 1.0f / float(shadowMapInfo.atlasDimension);
|
||||||
case ShadowType::DIRECTIONAL:
|
const float4 v = float4{ l, b, l + w, b + h } * texel;
|
||||||
// For directional lights, we need to allow the sampling to reach the border, it
|
|
||||||
// happens when "focus shadow casters" is used for instance.
|
|
||||||
border = 0.5f;
|
|
||||||
break;
|
|
||||||
case ShadowType::SPOT:
|
|
||||||
case ShadowType::POINT:
|
|
||||||
// For spot and point light, this is equal to the viewport. i.e. the valid
|
|
||||||
// texels are inside the viewport (w/ 1-texel border), the border will be used
|
|
||||||
// for bilinear filtering.
|
|
||||||
border = 1.0f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
float const texel = 1.0f / float(shadowMapInfo.atlasDimension);
|
|
||||||
float const dim = float(mOptions->mapSize);
|
|
||||||
float const l = border;
|
|
||||||
float const b = border;
|
|
||||||
float const w = dim - 2.0f * border;
|
|
||||||
float const h = dim - 2.0f * border;
|
|
||||||
float4 const v = float4{ l, b, l + w, b + h } * texel;
|
|
||||||
if (shadowMapInfo.textureSpaceFlipped) {
|
if (shadowMapInfo.textureSpaceFlipped) {
|
||||||
// this is equivalent to calling uvToRenderTargetUV() in the shader *after* clamping
|
// this is equivalent to calling uvToRenderTargetUV() in the shader *after* clamping
|
||||||
// texture coordinates to this normalized viewport.
|
// texture coordinates to this normalized viewport.
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ private:
|
|||||||
const math::float3& dir);
|
const math::float3& dir);
|
||||||
|
|
||||||
static inline void snapLightFrustum(math::float2& s, math::float2& o,
|
static inline void snapLightFrustum(math::float2& s, math::float2& o,
|
||||||
math::mat4f const& Mv, math::double3 wsSnapCoords, math::int2 resolution) noexcept;
|
math::mat4f const& Mv, math::float3 worldOrigin, math::float2 shadowMapResolution) noexcept;
|
||||||
|
|
||||||
static inline void computeFrustumCorners(math::float3* out,
|
static inline void computeFrustumCorners(math::float3* out,
|
||||||
const math::mat4f& projectionViewInverse, math::float2 csNearFar = { -1.0f, 1.0f }) noexcept;
|
const math::mat4f& projectionViewInverse, math::float2 csNearFar = { -1.0f, 1.0f }) noexcept;
|
||||||
@@ -281,13 +281,13 @@ private:
|
|||||||
static math::mat4f computeVsmLightSpaceMatrix(const math::mat4f& lightSpacePcf,
|
static math::mat4f computeVsmLightSpaceMatrix(const math::mat4f& lightSpacePcf,
|
||||||
const math::mat4f& Mv, float znear, float zfar) noexcept;
|
const math::mat4f& Mv, float znear, float zfar) noexcept;
|
||||||
|
|
||||||
math::float4 getClampToEdgeCoords(ShadowMapInfo const& shadowMapInfo) const noexcept;
|
math::float4 getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept;
|
||||||
|
|
||||||
static float texelSizeWorldSpace(const math::mat3f& worldToShadowTexture,
|
float texelSizeWorldSpace(const math::mat3f& worldToShadowTexture,
|
||||||
uint16_t shadowDimension) noexcept;
|
uint16_t shadowDimension) const noexcept;
|
||||||
|
|
||||||
static float texelSizeWorldSpace(const math::mat4f& W, const math::mat4f& MbMtF,
|
float texelSizeWorldSpace(const math::mat4f& W, const math::mat4f& MbMtF,
|
||||||
uint16_t shadowDimension) noexcept;
|
uint16_t shadowDimension) const noexcept;
|
||||||
|
|
||||||
static constexpr const Segment sBoxSegments[12] = {
|
static constexpr const Segment sBoxSegments[12] = {
|
||||||
{ 0, 1 }, { 1, 3 }, { 3, 2 }, { 2, 0 },
|
{ 0, 1 }, { 1, 3 }, { 3, 2 }, { 2, 0 },
|
||||||
|
|||||||
@@ -435,9 +435,8 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEngine& engine,
|
ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEngine& engine,
|
||||||
FView& view, CameraInfo cameraInfo, FScene::RenderableSoa& renderableData,
|
FView& view, CameraInfo const& cameraInfo, FScene::RenderableSoa& renderableData,
|
||||||
FScene::LightSoa const& lightData, ShadowMap::SceneInfo sceneInfo) noexcept {
|
FScene::LightSoa const& lightData, ShadowMap::SceneInfo sceneInfo) noexcept {
|
||||||
|
|
||||||
FScene* scene = view.getScene();
|
FScene* scene = view.getScene();
|
||||||
auto& lcm = engine.getLightManager();
|
auto& lcm = engine.getLightManager();
|
||||||
|
|
||||||
@@ -445,24 +444,6 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
|||||||
FLightManager::ShadowOptions const& options = lcm.getShadowOptions(directionalLight);
|
FLightManager::ShadowOptions const& options = lcm.getShadowOptions(directionalLight);
|
||||||
FLightManager::ShadowParams const& params = lcm.getShadowParams(directionalLight);
|
FLightManager::ShadowParams const& params = lcm.getShadowParams(directionalLight);
|
||||||
|
|
||||||
// Adjust the camera's projection for the light's shadowFar
|
|
||||||
|
|
||||||
cameraInfo.zf = params.options.shadowFar > 0.0f ? params.options.shadowFar : cameraInfo.zf;
|
|
||||||
if (UTILS_UNLIKELY(params.options.shadowFar > 0.0f)) {
|
|
||||||
cameraInfo.zf = params.options.shadowFar;
|
|
||||||
float const n = cameraInfo.zn;
|
|
||||||
float const f = cameraInfo.zf;
|
|
||||||
if (std::abs(cameraInfo.cullingProjection[2].w) > std::numeric_limits<float>::epsilon()) {
|
|
||||||
// perspective projection
|
|
||||||
cameraInfo.cullingProjection[2].z = (f + n) / (n - f);
|
|
||||||
cameraInfo.cullingProjection[3].z = (2 * f * n) / (n - f);
|
|
||||||
} else {
|
|
||||||
// orthographic projection
|
|
||||||
cameraInfo.cullingProjection[2].z = 2.0f / (n - f);
|
|
||||||
cameraInfo.cullingProjection[3].z = (f + n) / (n - f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShadowMap::ShadowMapInfo shadowMapInfo{
|
const ShadowMap::ShadowMapInfo shadowMapInfo{
|
||||||
.atlasDimension = mTextureAtlasRequirements.size,
|
.atlasDimension = mTextureAtlasRequirements.size,
|
||||||
.textureDimension = uint16_t(options.mapSize),
|
.textureDimension = uint16_t(options.mapSize),
|
||||||
@@ -478,7 +459,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
|||||||
// entire camera frustum, as if we only had a single cascade.
|
// entire camera frustum, as if we only had a single cascade.
|
||||||
ShadowMap& shadowMap = *mCascadeShadowMaps[0];
|
ShadowMap& shadowMap = *mCascadeShadowMaps[0];
|
||||||
|
|
||||||
const auto direction = options.transform * lightData.elementAt<FScene::DIRECTION>(0);
|
const auto direction = lightData.elementAt<FScene::DIRECTION>(0);
|
||||||
|
|
||||||
// We compute the directional light's model matrix using the origin's as the light position.
|
// We compute the directional light's model matrix using the origin's as the light position.
|
||||||
// The choice of the light's origin initially doesn't matter for a directional light.
|
// The choice of the light's origin initially doesn't matter for a directional light.
|
||||||
@@ -523,13 +504,19 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
|||||||
splitPercentages[i] = options.cascadeSplitPositions[i - 1];
|
splitPercentages[i] = options.cascadeSplitPositions[i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CascadeSplits splits({
|
const CascadeSplits::Params p{
|
||||||
.proj = cameraInfo.cullingProjection,
|
.proj = cameraInfo.cullingProjection,
|
||||||
.near = vsNear,
|
.near = vsNear,
|
||||||
.far = vsFar,
|
.far = vsFar,
|
||||||
.cascadeCount = cascadeCount,
|
.cascadeCount = cascadeCount,
|
||||||
.splitPositions = splitPercentages
|
.splitPositions = splitPercentages
|
||||||
});
|
};
|
||||||
|
if (p != mCascadeSplitParams) {
|
||||||
|
mCascadeSplits = CascadeSplits{ p };
|
||||||
|
mCascadeSplitParams = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CascadeSplits& splits = mCascadeSplits;
|
||||||
|
|
||||||
// The split positions uniform is a float4. To save space, we chop off the first split position
|
// The split positions uniform is a float4. To save space, we chop off the first split position
|
||||||
// (which is the near plane, and doesn't need to be communicated to the shaders).
|
// (which is the near plane, and doesn't need to be communicated to the shaders).
|
||||||
@@ -543,7 +530,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
|||||||
|
|
||||||
mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform;
|
mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform;
|
||||||
|
|
||||||
// When computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||||
// note: normalBias is set to zero for VSM
|
// note: normalBias is set to zero for VSM
|
||||||
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ShadowMapManager::ShadowTechnique updateCascadeShadowMaps(FEngine& engine,
|
ShadowMapManager::ShadowTechnique updateCascadeShadowMaps(FEngine& engine,
|
||||||
FView& view, CameraInfo cameraInfo, FScene::RenderableSoa& renderableData,
|
FView& view, CameraInfo const& cameraInfo, FScene::RenderableSoa& renderableData,
|
||||||
FScene::LightSoa const& lightData, ShadowMap::SceneInfo sceneInfo) noexcept;
|
FScene::LightSoa const& lightData, ShadowMap::SceneInfo sceneInfo) noexcept;
|
||||||
|
|
||||||
ShadowMapManager::ShadowTechnique updateSpotShadowMaps(FEngine& engine,
|
ShadowMapManager::ShadowTechnique updateSpotShadowMaps(FEngine& engine,
|
||||||
@@ -145,8 +145,17 @@ private:
|
|||||||
float far = 0.0f;
|
float far = 0.0f;
|
||||||
size_t cascadeCount = 1;
|
size_t cascadeCount = 1;
|
||||||
std::array<float, SPLIT_COUNT> splitPositions = { 0.0f };
|
std::array<float, SPLIT_COUNT> splitPositions = { 0.0f };
|
||||||
|
|
||||||
|
bool operator!=(const Params& rhs) const {
|
||||||
|
return proj != rhs.proj ||
|
||||||
|
near != rhs.near ||
|
||||||
|
far != rhs.far ||
|
||||||
|
cascadeCount != rhs.cascadeCount ||
|
||||||
|
splitPositions != rhs.splitPositions;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CascadeSplits() noexcept : CascadeSplits(Params{}) {}
|
||||||
explicit CascadeSplits(Params const& params) noexcept;
|
explicit CascadeSplits(Params const& params) noexcept;
|
||||||
|
|
||||||
// Split positions in world-space.
|
// Split positions in world-space.
|
||||||
@@ -177,6 +186,9 @@ private:
|
|||||||
|
|
||||||
SoftShadowOptions mSoftShadowOptions;
|
SoftShadowOptions mSoftShadowOptions;
|
||||||
|
|
||||||
|
CascadeSplits::Params mCascadeSplitParams;
|
||||||
|
CascadeSplits mCascadeSplits;
|
||||||
|
|
||||||
mutable TypedUniformBuffer<ShadowUib> mShadowUb;
|
mutable TypedUniformBuffer<ShadowUib> mShadowUb;
|
||||||
backend::Handle<backend::HwBufferObject> mShadowUbh;
|
backend::Handle<backend::HwBufferObject> mShadowUbh;
|
||||||
|
|
||||||
@@ -192,8 +204,8 @@ private:
|
|||||||
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
||||||
CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
|
CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
|
||||||
|
|
||||||
// Inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
|
// inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
|
||||||
// Because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
|
// because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
|
||||||
// Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps)
|
// Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps)
|
||||||
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
|
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
|
||||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
||||||
|
|||||||
@@ -127,12 +127,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isSpotLight(Instance i) const noexcept {
|
bool isSpotLight(Instance i) const noexcept {
|
||||||
Type const type = getType(i);
|
Type type = getType(i);
|
||||||
return type == Type::FOCUSED_SPOT || type == Type::SPOT;
|
return type == Type::FOCUSED_SPOT || type == Type::SPOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDirectionalLight(Instance i) const noexcept {
|
bool isDirectionalLight(Instance i) const noexcept {
|
||||||
Type const type = getType(i);
|
Type type = getType(i);
|
||||||
return type == Type::DIRECTIONAL || type == Type::SUN;
|
return type == Type::DIRECTIONAL || type == Type::SUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
Pod::Spec.new do |spec|
|
Pod::Spec.new do |spec|
|
||||||
spec.name = "Filament"
|
spec.name = "Filament"
|
||||||
spec.version = "1.43.0"
|
spec.version = "1.42.0"
|
||||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||||
spec.homepage = "https://google.github.io/filament"
|
spec.homepage = "https://google.github.io/filament"
|
||||||
spec.authors = "Google LLC."
|
spec.authors = "Google LLC."
|
||||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||||
spec.platform = :ios, "11.0"
|
spec.platform = :ios, "11.0"
|
||||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.43.0/filament-v1.43.0-ios.tgz" }
|
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.42.0/filament-v1.42.0-ios.tgz" }
|
||||||
|
|
||||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||||
spec.pod_target_xcconfig = {
|
spec.pod_target_xcconfig = {
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
#ifndef TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
#ifndef TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
||||||
#define TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
#define TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <math/vec2.h>
|
#include <math/vec2.h>
|
||||||
#include <math/vec3.h>
|
#include <math/vec3.h>
|
||||||
#include <math/vec4.h>
|
#include <math/vec4.h>
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
#ifndef TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
#ifndef TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
||||||
#define TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
#define TNT_FILAMENT_SAMPLE_CAMERA_MANIPULATOR_H
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <math/vec2.h>
|
#include <math/vec2.h>
|
||||||
#include <math/vec3.h>
|
#include <math/vec3.h>
|
||||||
#include <math/vec4.h>
|
#include <math/vec4.h>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
// update this when a new version of filament wouldn't work with older materials
|
// update this when a new version of filament wouldn't work with older materials
|
||||||
static constexpr size_t MATERIAL_VERSION = 43;
|
static constexpr size_t MATERIAL_VERSION = 42;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported shading models
|
* Supported shading models
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ for example, `filament-20181009-linux.tgz`.
|
|||||||
|
|
||||||
Create a file, `main.cpp`, in the same directory with the following contents:
|
Create a file, `main.cpp`, in the same directory with the following contents:
|
||||||
|
|
||||||
```c++
|
```
|
||||||
#include <filamat/MaterialBuilder.h>
|
#include <filamat/MaterialBuilder.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -85,7 +85,7 @@ Copy your platform's Makefile below into a `Makefile` inside the same directory.
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=-lfilamat -lfilabridge -lshaders -lutils -lsmol-v
|
FILAMENT_LIBS=-lfilamat -lfilabridge -lshaders -lutils -lsmol-v
|
||||||
CC=clang++
|
CC=clang++
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ clean:
|
|||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=-lfilamat -lfilabridge -lshaders -lutils -lsmol-v
|
FILAMENT_LIBS=-lfilamat -lfilabridge -lshaders -lutils -lsmol-v
|
||||||
CC=clang++
|
CC=clang++
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ flags](https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-tim
|
|||||||
When building Filamat from source, the `USE_STATIC_CRT` CMake option can be
|
When building Filamat from source, the `USE_STATIC_CRT` CMake option can be
|
||||||
used to change the run-time library version.
|
used to change the run-time library version.
|
||||||
|
|
||||||
```make
|
```
|
||||||
FILAMENT_LIBS=lib/x86_64/mt/filamat.lib lib/x86_64/mt/filabridge.lib lib/x86_64/mt/shaders.lib \
|
FILAMENT_LIBS=lib/x86_64/mt/filamat.lib lib/x86_64/mt/filabridge.lib lib/x86_64/mt/shaders.lib \
|
||||||
lib/x86_64/mt/utils.lib lib/x86_64/mt/smol-v.lib
|
lib/x86_64/mt/utils.lib lib/x86_64/mt/smol-v.lib
|
||||||
CC=clang-cl.exe
|
CC=clang-cl.exe
|
||||||
@@ -164,7 +164,7 @@ and invoke `nmake` instead of `make`.
|
|||||||
For simplicity, this demo doesn't do anything useful with the built material package. To use the
|
For simplicity, this demo doesn't do anything useful with the built material package. To use the
|
||||||
material with Filament, pass the material package's data into a Filament Material builder:
|
material with Filament, pass the material package's data into a Filament Material builder:
|
||||||
|
|
||||||
```c++
|
```
|
||||||
Package package = builder.build();
|
Package package = builder.build();
|
||||||
filament::Material* myMaterial = Material::Builder()
|
filament::Material* myMaterial = Material::Builder()
|
||||||
.package(package.getData(), package.getSize())
|
.package(package.getData(), package.getSize())
|
||||||
@@ -186,7 +186,7 @@ In addition, `filamat_lite` only performs a simple text match to determine which
|
|||||||
`MaterialInputs` structure are set. The `material` input variable must also always be refered to by
|
`MaterialInputs` structure are set. The `material` input variable must also always be refered to by
|
||||||
the name `material`.
|
the name `material`.
|
||||||
|
|
||||||
```glsl
|
```
|
||||||
void anotherFunction(inout MaterialInputs m) {
|
void anotherFunction(inout MaterialInputs m) {
|
||||||
// Incorrect! The MaterialInputs is being referred to by the name "m".
|
// Incorrect! The MaterialInputs is being referred to by the name "m".
|
||||||
m.metallic = 0.0;
|
m.metallic = 0.0;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ set(PUBLIC_HDRS
|
|||||||
include/gltfio/FilamentInstance.h
|
include/gltfio/FilamentInstance.h
|
||||||
include/gltfio/MaterialProvider.h
|
include/gltfio/MaterialProvider.h
|
||||||
include/gltfio/NodeManager.h
|
include/gltfio/NodeManager.h
|
||||||
include/gltfio/TrsTransformManager.h
|
|
||||||
include/gltfio/ResourceLoader.h
|
include/gltfio/ResourceLoader.h
|
||||||
include/gltfio/TextureProvider.h
|
include/gltfio/TextureProvider.h
|
||||||
include/gltfio/math.h
|
include/gltfio/math.h
|
||||||
@@ -36,12 +35,10 @@ set(SRCS
|
|||||||
src/FilamentAsset.cpp
|
src/FilamentAsset.cpp
|
||||||
src/FilamentInstance.cpp
|
src/FilamentInstance.cpp
|
||||||
src/FNodeManager.h
|
src/FNodeManager.h
|
||||||
src/FTrsTransformManager.h
|
|
||||||
src/GltfEnums.h
|
src/GltfEnums.h
|
||||||
src/Ktx2Provider.cpp
|
src/Ktx2Provider.cpp
|
||||||
src/MaterialProvider.cpp
|
src/MaterialProvider.cpp
|
||||||
src/NodeManager.cpp
|
src/NodeManager.cpp
|
||||||
src/TrsTransformManager.cpp
|
|
||||||
src/ResourceLoader.cpp
|
src/ResourceLoader.cpp
|
||||||
src/StbProvider.cpp
|
src/StbProvider.cpp
|
||||||
src/TangentsJob.cpp
|
src/TangentsJob.cpp
|
||||||
@@ -189,7 +186,8 @@ if (NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
|||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Compiler flags
|
# Compiler flags
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
if (NOT MSVC)
|
if (MSVC)
|
||||||
|
else()
|
||||||
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -227,9 +225,7 @@ if (TNT_DEV AND NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
|||||||
add_dependencies(${TEST_TARGET} test_gltfio_files)
|
add_dependencies(${TEST_TARGET} test_gltfio_files)
|
||||||
|
|
||||||
target_link_libraries(${TEST_TARGET} PRIVATE ${TARGET} filament filabridge gtest uberarchive)
|
target_link_libraries(${TEST_TARGET} PRIVATE ${TARGET} filament filabridge gtest uberarchive)
|
||||||
if (NOT MSVC)
|
target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-register)
|
||||||
target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-register)
|
|
||||||
endif()
|
|
||||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER Tests)
|
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER Tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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 GLTFIO_TRSTRANSFORMMANAGER_H
|
|
||||||
#define GLTFIO_TRSTRANSFORMMANAGER_H
|
|
||||||
|
|
||||||
#include <filament/FilamentAPI.h>
|
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
|
||||||
#include <utils/EntityInstance.h>
|
|
||||||
#include <math/quat.h>
|
|
||||||
#include <math/vec3.h>
|
|
||||||
#include <math/mat4.h>
|
|
||||||
|
|
||||||
using namespace filament::math;
|
|
||||||
|
|
||||||
namespace utils {
|
|
||||||
class Entity;
|
|
||||||
} // namespace utils
|
|
||||||
|
|
||||||
namespace filament::gltfio {
|
|
||||||
|
|
||||||
class FTrsTransformManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TrsTransformManager is used to add entities with glTF-specific trs information.
|
|
||||||
*
|
|
||||||
* Trs information here just used for Animation, DON'T use for transform.
|
|
||||||
*/
|
|
||||||
class UTILS_PUBLIC TrsTransformManager {
|
|
||||||
public:
|
|
||||||
using Instance = utils::EntityInstance<TrsTransformManager>;
|
|
||||||
using Entity = utils::Entity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a particular Entity is associated with a component of this TrsTransformManager
|
|
||||||
* @param e An Entity.
|
|
||||||
* @return true if this Entity has a component associated with this manager.
|
|
||||||
*/
|
|
||||||
bool hasComponent(Entity e) const noexcept;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an Instance representing the trs transform component associated with the given Entity.
|
|
||||||
* @param e An Entity.
|
|
||||||
* @return An Instance object, which represents the trs transform component associated with the Entity e.
|
|
||||||
* @note Use Instance::isValid() to make sure the component exists.
|
|
||||||
* @see hasComponent()
|
|
||||||
*/
|
|
||||||
Instance getInstance(Entity e) const noexcept;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trs transform component and associates it with the given entity.
|
|
||||||
* @param entity An Entity to associate a trs transform component with.
|
|
||||||
* @param translation The translation to initialize the trs transform component with.
|
|
||||||
* @param rotation The rotation to initialize the trs transform component with.
|
|
||||||
* @param scale The scale to initialize the trs transform component with.
|
|
||||||
*
|
|
||||||
* If this component already exists on the given entity, it is first destroyed as if
|
|
||||||
* destroy(Entity e) was called.
|
|
||||||
*
|
|
||||||
* @see destroy()
|
|
||||||
*/
|
|
||||||
void create(Entity entity);
|
|
||||||
void create(Entity entity, const float3& translation, const quatf& rotation,
|
|
||||||
const float3& scale); //!< \overload
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys this component from the given entity.
|
|
||||||
* @param e An entity.
|
|
||||||
*
|
|
||||||
* @see create()
|
|
||||||
*/
|
|
||||||
void destroy(Entity e) noexcept;
|
|
||||||
|
|
||||||
void setTranslation(Instance ci, const float3& translation) noexcept;
|
|
||||||
const float3& getTranslation(Instance ci) const noexcept;
|
|
||||||
|
|
||||||
void setRotation(Instance ci, const quatf& rotation) noexcept;
|
|
||||||
const quatf& getRotation(Instance ci) const noexcept;
|
|
||||||
|
|
||||||
void setScale(Instance ci, const float3& scale) noexcept;
|
|
||||||
const float3& getScale(Instance ci) const noexcept;
|
|
||||||
|
|
||||||
void setTrs(Instance ci, const float3& translation, const quatf& rotation,
|
|
||||||
const float3& scale) noexcept;
|
|
||||||
const mat4f getTransform(Instance ci) const noexcept;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
TrsTransformManager() noexcept = default;
|
|
||||||
~TrsTransformManager() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TrsTransformManager(TrsTransformManager const&) = delete;
|
|
||||||
TrsTransformManager(TrsTransformManager&&) = delete;
|
|
||||||
TrsTransformManager& operator=(TrsTransformManager const&) = delete;
|
|
||||||
TrsTransformManager& operator=(TrsTransformManager&&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace filament::gltfio
|
|
||||||
|
|
||||||
#endif // GLTFIO_TRSTRANSFORMMANAGER_H
|
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "FFilamentAsset.h"
|
#include "FFilamentAsset.h"
|
||||||
#include "FFilamentInstance.h"
|
#include "FFilamentInstance.h"
|
||||||
#include "FTrsTransformManager.h"
|
|
||||||
#include "downcast.h"
|
#include "downcast.h"
|
||||||
|
|
||||||
#include <filament/VertexBuffer.h>
|
#include <filament/VertexBuffer.h>
|
||||||
@@ -75,7 +74,6 @@ struct AnimatorImpl {
|
|||||||
FFilamentInstance* instance = nullptr;
|
FFilamentInstance* instance = nullptr;
|
||||||
RenderableManager* renderableManager;
|
RenderableManager* renderableManager;
|
||||||
TransformManager* transformManager;
|
TransformManager* transformManager;
|
||||||
TrsTransformManager* trsTransformManager;
|
|
||||||
vector<float> weights;
|
vector<float> weights;
|
||||||
FixedCapacityVector<mat4f> crossFade;
|
FixedCapacityVector<mat4f> crossFade;
|
||||||
void addChannels(const FixedCapacityVector<Entity>& nodeMap, const cgltf_animation& srcAnim,
|
void addChannels(const FixedCapacityVector<Entity>& nodeMap, const cgltf_animation& srcAnim,
|
||||||
@@ -192,7 +190,6 @@ Animator::Animator(FFilamentAsset const* asset, FFilamentInstance* instance) {
|
|||||||
mImpl->instance = instance;
|
mImpl->instance = instance;
|
||||||
mImpl->renderableManager = &asset->mEngine->getRenderableManager();
|
mImpl->renderableManager = &asset->mEngine->getRenderableManager();
|
||||||
mImpl->transformManager = &asset->mEngine->getTransformManager();
|
mImpl->transformManager = &asset->mEngine->getTransformManager();
|
||||||
mImpl->trsTransformManager = asset->getTrsTransformManager();
|
|
||||||
|
|
||||||
const cgltf_data* srcAsset = asset->mSourceAsset->hierarchy;
|
const cgltf_data* srcAsset = asset->mSourceAsset->hierarchy;
|
||||||
const cgltf_animation* srcAnims = srcAsset->animations;
|
const cgltf_animation* srcAnims = srcAsset->animations;
|
||||||
@@ -432,13 +429,20 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
|
|||||||
size_t nextIndex) {
|
size_t nextIndex) {
|
||||||
const Sampler* sampler = channel.sourceData;
|
const Sampler* sampler = channel.sourceData;
|
||||||
const TimeValues& times = sampler->times;
|
const TimeValues& times = sampler->times;
|
||||||
TrsTransformManager::Instance trsNode = trsTransformManager->getInstance(channel.targetEntity);
|
|
||||||
TransformManager::Instance node = transformManager->getInstance(channel.targetEntity);
|
TransformManager::Instance node = transformManager->getInstance(channel.targetEntity);
|
||||||
|
|
||||||
|
// Perform the interpolation. This is a simple but inefficient implementation; Filament
|
||||||
|
// stores transforms as mat4's but glTF animation is based on TRS (translation rotation
|
||||||
|
// scale).
|
||||||
|
mat4f xform = transformManager->getTransform(node);
|
||||||
|
float3 scale;
|
||||||
|
quatf rotation;
|
||||||
|
float3 translation;
|
||||||
|
decomposeMatrix(xform, &translation, &rotation, &scale);
|
||||||
|
|
||||||
switch (channel.transformType) {
|
switch (channel.transformType) {
|
||||||
|
|
||||||
case Channel::SCALE: {
|
case Channel::SCALE: {
|
||||||
float3 scale;
|
|
||||||
const float3* srcVec3 = (const float3*) sampler->values.data();
|
const float3* srcVec3 = (const float3*) sampler->values.data();
|
||||||
if (sampler->interpolation == Sampler::CUBIC) {
|
if (sampler->interpolation == Sampler::CUBIC) {
|
||||||
float3 vert0 = srcVec3[prevIndex * 3 + 1];
|
float3 vert0 = srcVec3[prevIndex * 3 + 1];
|
||||||
@@ -449,12 +453,10 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
|
|||||||
} else {
|
} else {
|
||||||
scale = ((1 - t) * srcVec3[prevIndex]) + (t * srcVec3[nextIndex]);
|
scale = ((1 - t) * srcVec3[prevIndex]) + (t * srcVec3[nextIndex]);
|
||||||
}
|
}
|
||||||
trsTransformManager->setScale(trsNode, scale);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Channel::TRANSLATION: {
|
case Channel::TRANSLATION: {
|
||||||
float3 translation;
|
|
||||||
const float3* srcVec3 = (const float3*) sampler->values.data();
|
const float3* srcVec3 = (const float3*) sampler->values.data();
|
||||||
if (sampler->interpolation == Sampler::CUBIC) {
|
if (sampler->interpolation == Sampler::CUBIC) {
|
||||||
float3 vert0 = srcVec3[prevIndex * 3 + 1];
|
float3 vert0 = srcVec3[prevIndex * 3 + 1];
|
||||||
@@ -465,12 +467,10 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
|
|||||||
} else {
|
} else {
|
||||||
translation = ((1 - t) * srcVec3[prevIndex]) + (t * srcVec3[nextIndex]);
|
translation = ((1 - t) * srcVec3[prevIndex]) + (t * srcVec3[nextIndex]);
|
||||||
}
|
}
|
||||||
trsTransformManager->setTranslation(trsNode, translation);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Channel::ROTATION: {
|
case Channel::ROTATION: {
|
||||||
quatf rotation;
|
|
||||||
const quatf* srcQuat = (const quatf*) sampler->values.data();
|
const quatf* srcQuat = (const quatf*) sampler->values.data();
|
||||||
if (sampler->interpolation == Sampler::CUBIC) {
|
if (sampler->interpolation == Sampler::CUBIC) {
|
||||||
quatf vert0 = srcQuat[prevIndex * 3 + 1];
|
quatf vert0 = srcQuat[prevIndex * 3 + 1];
|
||||||
@@ -481,7 +481,6 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
|
|||||||
} else {
|
} else {
|
||||||
rotation = slerp(srcQuat[prevIndex], srcQuat[nextIndex], t);
|
rotation = slerp(srcQuat[prevIndex], srcQuat[nextIndex], t);
|
||||||
}
|
}
|
||||||
trsTransformManager->setRotation(trsNode, rotation);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +519,8 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transformManager->setTransform(node, trsTransformManager->getTransform(trsNode));
|
xform = composeMatrix(translation, rotation, scale);
|
||||||
|
transformManager->setTransform(node, xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimatorImpl::resetBoneMatrices(FFilamentInstance* instance) {
|
void AnimatorImpl::resetBoneMatrices(FFilamentInstance* instance) {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include "FFilamentAsset.h"
|
#include "FFilamentAsset.h"
|
||||||
#include "FNodeManager.h"
|
#include "FNodeManager.h"
|
||||||
#include "FTrsTransformManager.h"
|
|
||||||
#include "GltfEnums.h"
|
#include "GltfEnums.h"
|
||||||
|
|
||||||
#include <filament/Box.h>
|
#include <filament/Box.h>
|
||||||
@@ -296,7 +295,6 @@ public:
|
|||||||
MaterialProvider& mMaterials;
|
MaterialProvider& mMaterials;
|
||||||
Engine& mEngine;
|
Engine& mEngine;
|
||||||
FNodeManager mNodeManager;
|
FNodeManager mNodeManager;
|
||||||
FTrsTransformManager mTrsTransformManager;
|
|
||||||
|
|
||||||
// Transient state used only for the asset currently being loaded:
|
// Transient state used only for the asset currently being loaded:
|
||||||
FFilamentAsset* mAsset;
|
FFilamentAsset* mAsset;
|
||||||
@@ -402,8 +400,7 @@ void FAssetLoader::createRootAsset(const cgltf_data* srcAsset) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
mDummyBufferObject = nullptr;
|
mDummyBufferObject = nullptr;
|
||||||
mAsset = new FFilamentAsset(&mEngine, mNameManager, &mEntityManager, &mNodeManager,
|
mAsset = new FFilamentAsset(&mEngine, mNameManager, &mEntityManager, &mNodeManager, srcAsset);
|
||||||
&mTrsTransformManager, srcAsset);
|
|
||||||
|
|
||||||
// It is not an error for a glTF file to have zero scenes.
|
// It is not an error for a glTF file to have zero scenes.
|
||||||
mAsset->mScenes.clear();
|
mAsset->mScenes.clear();
|
||||||
@@ -566,9 +563,7 @@ void FAssetLoader::recurseEntities(const cgltf_data* srcAsset, const cgltf_node*
|
|||||||
quatf* rotation = (quatf*) &node->rotation[0];
|
quatf* rotation = (quatf*) &node->rotation[0];
|
||||||
float3* scale = (float3*) &node->scale[0];
|
float3* scale = (float3*) &node->scale[0];
|
||||||
float3* translation = (float3*) &node->translation[0];
|
float3* translation = (float3*) &node->translation[0];
|
||||||
mTrsTransformManager.create(entity, *translation, *rotation, *scale);
|
localTransform = composeMatrix(*translation, *rotation, *scale);
|
||||||
localTransform = mTrsTransformManager.getTransform(
|
|
||||||
mTrsTransformManager.getInstance(entity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parentTransform = mTransformManager.getInstance(parent);
|
auto parentTransform = mTransformManager.getInstance(parent);
|
||||||
@@ -1472,9 +1467,8 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (matkey.hasSheenRoughnessTexture) {
|
if (matkey.hasSheenRoughnessTexture) {
|
||||||
bool sameTexture = shConfig.sheen_color_texture.texture == shConfig.sheen_roughness_texture.texture;
|
|
||||||
mAsset->addTextureBinding(mi, "sheenRoughnessMap",
|
mAsset->addTextureBinding(mi, "sheenRoughnessMap",
|
||||||
shConfig.sheen_roughness_texture.texture, sameTexture ? sRGB : LINEAR);
|
shConfig.sheen_roughness_texture.texture, LINEAR);
|
||||||
if (matkey.hasTextureTransforms) {
|
if (matkey.hasTextureTransforms) {
|
||||||
const cgltf_texture_transform& uvt = shConfig.sheen_roughness_texture.transform;
|
const cgltf_texture_transform& uvt = shConfig.sheen_roughness_texture.transform;
|
||||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <gltfio/FilamentAsset.h>
|
#include <gltfio/FilamentAsset.h>
|
||||||
#include <gltfio/NodeManager.h>
|
#include <gltfio/NodeManager.h>
|
||||||
#include <gltfio/TrsTransformManager.h>
|
|
||||||
|
|
||||||
#include <filament/Engine.h>
|
#include <filament/Engine.h>
|
||||||
#include <filament/IndexBuffer.h>
|
#include <filament/IndexBuffer.h>
|
||||||
@@ -111,9 +110,9 @@ using MeshCache = utils::FixedCapacityVector<utils::FixedCapacityVector<Primitiv
|
|||||||
struct FFilamentAsset : public FilamentAsset {
|
struct FFilamentAsset : public FilamentAsset {
|
||||||
FFilamentAsset(Engine* engine, utils::NameComponentManager* names,
|
FFilamentAsset(Engine* engine, utils::NameComponentManager* names,
|
||||||
utils::EntityManager* entityManager, NodeManager* nodeManager,
|
utils::EntityManager* entityManager, NodeManager* nodeManager,
|
||||||
TrsTransformManager* trsTransformManager, const cgltf_data* srcAsset) :
|
const cgltf_data* srcAsset) :
|
||||||
mEngine(engine), mNameManager(names), mEntityManager(entityManager),
|
mEngine(engine), mNameManager(names), mEntityManager(entityManager),
|
||||||
mNodeManager(nodeManager), mTrsTransformManager(trsTransformManager),
|
mNodeManager(nodeManager),
|
||||||
mSourceAsset(new SourceAsset {(cgltf_data*)srcAsset}),
|
mSourceAsset(new SourceAsset {(cgltf_data*)srcAsset}),
|
||||||
mTextures(srcAsset->textures_count),
|
mTextures(srcAsset->textures_count),
|
||||||
mMeshCache(srcAsset->meshes_count) {}
|
mMeshCache(srcAsset->meshes_count) {}
|
||||||
@@ -196,10 +195,6 @@ struct FFilamentAsset : public FilamentAsset {
|
|||||||
return mEngine;
|
return mEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrsTransformManager* getTrsTransformManager() const noexcept {
|
|
||||||
return mTrsTransformManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
void releaseSourceData() noexcept;
|
void releaseSourceData() noexcept;
|
||||||
|
|
||||||
const void* getSourceAsset() const noexcept {
|
const void* getSourceAsset() const noexcept {
|
||||||
@@ -247,7 +242,6 @@ struct FFilamentAsset : public FilamentAsset {
|
|||||||
utils::NameComponentManager* const mNameManager;
|
utils::NameComponentManager* const mNameManager;
|
||||||
utils::EntityManager* const mEntityManager;
|
utils::EntityManager* const mEntityManager;
|
||||||
NodeManager* const mNodeManager;
|
NodeManager* const mNodeManager;
|
||||||
TrsTransformManager* const mTrsTransformManager;
|
|
||||||
std::vector<utils::Entity> mEntities; // sorted such that renderables come first
|
std::vector<utils::Entity> mEntities; // sorted such that renderables come first
|
||||||
std::vector<utils::Entity> mLightEntities;
|
std::vector<utils::Entity> mLightEntities;
|
||||||
std::vector<utils::Entity> mCameraEntities;
|
std::vector<utils::Entity> mCameraEntities;
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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 GLTFIO_FTRSTRANSFORMMANAGER_H
|
|
||||||
#define GLTFIO_FTRSTRANSFORMMANAGER_H
|
|
||||||
|
|
||||||
#include "downcast.h"
|
|
||||||
#include "gltfio/math.h"
|
|
||||||
#include "math/quat.h"
|
|
||||||
#include "utils/debug.h"
|
|
||||||
|
|
||||||
#include <gltfio/TrsTransformManager.h>
|
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
|
||||||
#include <utils/SingleInstanceComponentManager.h>
|
|
||||||
#include <utils/Entity.h>
|
|
||||||
#include <utils/FixedCapacityVector.h>
|
|
||||||
#include <utils/Slice.h>
|
|
||||||
|
|
||||||
namespace filament::gltfio {
|
|
||||||
|
|
||||||
class UTILS_PRIVATE FTrsTransformManager : public TrsTransformManager {
|
|
||||||
public:
|
|
||||||
using Instance = TrsTransformManager::Instance;
|
|
||||||
|
|
||||||
FTrsTransformManager() noexcept {}
|
|
||||||
|
|
||||||
~FTrsTransformManager() noexcept {
|
|
||||||
assert_invariant(mManager.getComponentCount() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminate() noexcept;
|
|
||||||
|
|
||||||
bool hasComponent(utils::Entity e) const noexcept {
|
|
||||||
return mManager.hasComponent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Instance getInstance(utils::Entity e) const noexcept {
|
|
||||||
return Instance(mManager.getInstance(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
void create(utils::Entity entity) {
|
|
||||||
create(entity, float3{}, quatf{}, float3{1});
|
|
||||||
}
|
|
||||||
|
|
||||||
void create(utils::Entity entity, const float3& translation,
|
|
||||||
const quatf& rotation, const float3& scale) {
|
|
||||||
if (UTILS_UNLIKELY(mManager.hasComponent(entity))) {
|
|
||||||
destroy(entity);
|
|
||||||
}
|
|
||||||
UTILS_UNUSED_IN_RELEASE Instance ci = mManager.addComponent(entity);
|
|
||||||
assert_invariant(ci);
|
|
||||||
|
|
||||||
if (ci) {
|
|
||||||
setTrs(ci, translation, rotation, scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy(utils::Entity e) noexcept {
|
|
||||||
if (Instance ci = mManager.getInstance(e); ci) {
|
|
||||||
mManager.removeComponent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gc(utils::EntityManager& em) noexcept {
|
|
||||||
mManager.gc(em);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTranslation(Instance ci, const float3& translation) noexcept {
|
|
||||||
assert_invariant(ci.isValid());
|
|
||||||
mManager[ci].translation = translation;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float3& getTranslation(Instance ci) const noexcept {
|
|
||||||
return mManager[ci].translation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRotation(Instance ci, const quatf& rotation) noexcept {
|
|
||||||
assert_invariant(ci.isValid());
|
|
||||||
mManager[ci].rotation = rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
const quatf& getRotation(Instance ci) const noexcept {
|
|
||||||
return mManager[ci].rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScale(Instance ci, const float3& scale) noexcept {
|
|
||||||
assert_invariant(ci.isValid());
|
|
||||||
mManager[ci].scale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float3& getScale(Instance ci) const noexcept {
|
|
||||||
return mManager[ci].scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTrs(Instance ci, const float3& translation,
|
|
||||||
const quatf& rotation, const float3& scale) noexcept {
|
|
||||||
setTranslation(ci, translation);
|
|
||||||
setRotation(ci, rotation);
|
|
||||||
setScale(ci, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mat4f getTransform(Instance ci) const noexcept {
|
|
||||||
return composeMatrix(getTranslation(ci), getRotation(ci), getScale(ci));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
TRANSLATION,
|
|
||||||
ROTATION,
|
|
||||||
SCALE,
|
|
||||||
};
|
|
||||||
|
|
||||||
using Base = utils::SingleInstanceComponentManager<
|
|
||||||
float3,
|
|
||||||
quatf,
|
|
||||||
float3>;
|
|
||||||
|
|
||||||
struct Sim : public Base {
|
|
||||||
using Base::gc;
|
|
||||||
using Base::swap;
|
|
||||||
|
|
||||||
typename Base::SoA& getSoA() { return mData; }
|
|
||||||
|
|
||||||
struct Proxy {
|
|
||||||
UTILS_ALWAYS_INLINE
|
|
||||||
Proxy(Base& sim, utils::EntityInstanceBase::Type i) noexcept :
|
|
||||||
translation{ sim, i } { }
|
|
||||||
|
|
||||||
union {
|
|
||||||
Field<TRANSLATION> translation;
|
|
||||||
Field<ROTATION> rotation;
|
|
||||||
Field<SCALE> scale;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
UTILS_ALWAYS_INLINE Proxy operator[](Instance i) noexcept {
|
|
||||||
return { *this, i };
|
|
||||||
}
|
|
||||||
UTILS_ALWAYS_INLINE const Proxy operator[](Instance i) const noexcept {
|
|
||||||
return { const_cast<Sim&>(*this), i };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Sim mManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
FILAMENT_DOWNCAST(TrsTransformManager)
|
|
||||||
|
|
||||||
} // namespace filament::gltfio
|
|
||||||
|
|
||||||
#endif // GLTFIO_FTRSTRANSFORMMANAGER_H
|
|
||||||
@@ -60,11 +60,6 @@ FFilamentAsset::~FFilamentAsset() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy gltfio trs transform components.
|
|
||||||
for (auto entity : mEntities) {
|
|
||||||
mTrsTransformManager->destroy(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy all renderable, light, transform, and camera components,
|
// Destroy all renderable, light, transform, and camera components,
|
||||||
// then destroy the actual entities. This includes instances.
|
// then destroy the actual entities. This includes instances.
|
||||||
if (!mDetachedFilamentComponents) {
|
if (!mDetachedFilamentComponents) {
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ std::string shaderFromKey(const MaterialKey& config) {
|
|||||||
|
|
||||||
// TODO: Provided by Filament, but this should really be provided/computed by gltfio
|
// TODO: Provided by Filament, but this should really be provided/computed by gltfio
|
||||||
// TODO: This scale is per renderable and should include the scale of the mesh node
|
// TODO: This scale is per renderable and should include the scale of the mesh node
|
||||||
float scale = getObjectUserData();
|
float scale = object_uniforms.userData;
|
||||||
material.thickness = materialParams.volumeThicknessFactor * scale;
|
material.thickness = materialParams.volumeThicknessFactor * scale;
|
||||||
)SHADER";
|
)SHADER";
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2023 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 "FTrsTransformManager.h"
|
|
||||||
|
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
#include "downcast.h"
|
|
||||||
#include "gltfio/TrsTransformManager.h"
|
|
||||||
|
|
||||||
using namespace utils;
|
|
||||||
|
|
||||||
namespace filament::gltfio {
|
|
||||||
|
|
||||||
using Instance = TrsTransformManager::Instance;
|
|
||||||
|
|
||||||
void FTrsTransformManager::terminate() noexcept {
|
|
||||||
auto& manager = mManager;
|
|
||||||
if (!manager.empty()) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
utils::slog.d << "cleaning up " << manager.getComponentCount()
|
|
||||||
<< " leaked trs transform components" << utils::io::endl;
|
|
||||||
#endif
|
|
||||||
while (!manager.empty()) {
|
|
||||||
Instance ci = manager.end() - 1;
|
|
||||||
manager.removeComponent(manager.getEntity(ci));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TrsTransformManager::hasComponent(Entity e) const noexcept {
|
|
||||||
return downcast(this)->hasComponent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Instance TrsTransformManager::getInstance(Entity e) const noexcept {
|
|
||||||
return downcast(this)->getInstance(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::create(Entity entity) {
|
|
||||||
downcast(this)->create(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::create(Entity entity, const float3& translation,
|
|
||||||
const quatf& rotation, const float3& scale) {
|
|
||||||
downcast(this)->create(entity, translation, rotation, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::destroy(Entity e) noexcept {
|
|
||||||
downcast(this)->destroy(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::setTranslation(Instance ci, const float3& translation) noexcept {
|
|
||||||
downcast(this)->setTranslation(ci, translation);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float3& TrsTransformManager::getTranslation(Instance ci) const noexcept {
|
|
||||||
return downcast(this)->getTranslation(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::setRotation(Instance ci, const quatf& rotation) noexcept {
|
|
||||||
downcast(this)->setRotation(ci, rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
const quatf& TrsTransformManager::getRotation(Instance ci) const noexcept {
|
|
||||||
return downcast(this)->getRotation(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::setScale(Instance ci, const float3& scale) noexcept {
|
|
||||||
downcast(this)->setScale(ci, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float3& TrsTransformManager::getScale(Instance ci) const noexcept {
|
|
||||||
return downcast(this)->getScale(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrsTransformManager::setTrs(Instance ci, const float3& translation,
|
|
||||||
const quatf& rotation, const float3& scale) noexcept {
|
|
||||||
downcast(this)->setTrs(ci, translation, rotation, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mat4f TrsTransformManager::getTransform(Instance ci) const noexcept {
|
|
||||||
return downcast(this)->getTransform(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::gltfio
|
|
||||||
@@ -25,7 +25,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
namespace filament::math::details {
|
namespace filament {
|
||||||
|
namespace math {
|
||||||
|
namespace details {
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No user serviceable parts here.
|
* No user serviceable parts here.
|
||||||
@@ -46,7 +49,7 @@ namespace filament::math::details {
|
|||||||
template<template<typename T> class QUATERNION, typename T>
|
template<template<typename T> class QUATERNION, typename T>
|
||||||
class TQuatProductOperators {
|
class TQuatProductOperators {
|
||||||
public:
|
public:
|
||||||
/* compound assignment from another quaternion of the same size but different
|
/* compound assignment from a another quaternion of the same size but different
|
||||||
* element type.
|
* element type.
|
||||||
*/
|
*/
|
||||||
template<typename OTHER>
|
template<typename OTHER>
|
||||||
@@ -82,7 +85,7 @@ public:
|
|||||||
* (the first one, BASE<T> being known).
|
* (the first one, BASE<T> being known).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The operators below handle operation between quaternions of the same size
|
/* The operators below handle operation between quaternion of the same size
|
||||||
* but of a different element type.
|
* but of a different element type.
|
||||||
*/
|
*/
|
||||||
template<typename RT>
|
template<typename RT>
|
||||||
@@ -124,19 +127,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
friend inline
|
friend inline
|
||||||
constexpr QUATERNION<T> MATH_PURE operator*(QUATERNION<T> q, T scalar) {
|
constexpr QUATERNION<T> MATH_PURE operator*(QUATERNION<T> q, T scalar) {
|
||||||
// don't pass q by reference because we need a copy anyway
|
// don't pass q by reference because we need a copy anyways
|
||||||
return q *= scalar;
|
return q *= scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend inline
|
friend inline
|
||||||
constexpr QUATERNION<T> MATH_PURE operator*(T scalar, QUATERNION<T> q) {
|
constexpr QUATERNION<T> MATH_PURE operator*(T scalar, QUATERNION<T> q) {
|
||||||
// don't pass q by reference because we need a copy anyway
|
// don't pass q by reference because we need a copy anyways
|
||||||
return q *= scalar;
|
return q *= scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend inline
|
friend inline
|
||||||
constexpr QUATERNION<T> MATH_PURE operator/(QUATERNION<T> q, T scalar) {
|
constexpr QUATERNION<T> MATH_PURE operator/(QUATERNION<T> q, T scalar) {
|
||||||
// don't pass q by reference because we need a copy anyway
|
// don't pass q by reference because we need a copy anyways
|
||||||
return q /= scalar;
|
return q /= scalar;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -280,6 +283,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::math::details
|
// -------------------------------------------------------------------------------------
|
||||||
|
} // namespace details
|
||||||
|
} // namespace math
|
||||||
|
} // namespace filament
|
||||||
|
|
||||||
#endif // TNT_MATH_TQUATHELPERS_H
|
#endif // TNT_MATH_TQUATHELPERS_H
|
||||||
|
|||||||
@@ -443,37 +443,6 @@ private:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
friend inline
|
|
||||||
VECTOR<T> MATH_PURE fmod(VECTOR<T> const& x, VECTOR<U> const& y) {
|
|
||||||
VECTOR<T> r;
|
|
||||||
for (size_t i = 0; i < r.size(); i++) {
|
|
||||||
r[i] = std::fmod(x[i], y[i]);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
friend inline
|
|
||||||
VECTOR<T> MATH_PURE remainder(VECTOR<T> const& x, VECTOR<U> const& y) {
|
|
||||||
VECTOR<T> r;
|
|
||||||
for (size_t i = 0; i < r.size(); i++) {
|
|
||||||
r[i] = std::remainder(x[i], y[i]);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
friend inline
|
|
||||||
VECTOR<T> MATH_PURE remquo(VECTOR<T> const& x, VECTOR<U> const& y,
|
|
||||||
VECTOR<int>* q) {
|
|
||||||
VECTOR<T> r;
|
|
||||||
for (size_t i = 0; i < r.size(); i++) {
|
|
||||||
r[i] = std::remquo(x[i], y[i], &((*q)[i]));
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend inline VECTOR<T> MATH_PURE inversesqrt(VECTOR<T> v) {
|
friend inline VECTOR<T> MATH_PURE inversesqrt(VECTOR<T> v) {
|
||||||
for (size_t i = 0; i < v.size(); i++) {
|
for (size_t i = 0; i < v.size(); i++) {
|
||||||
v[i] = T(1) / std::sqrt(v[i]);
|
v[i] = T(1) / std::sqrt(v[i]);
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ constexpr inline half makeHalf(uint16_t bits) noexcept {
|
|||||||
|
|
||||||
#endif // __ARM_NEON
|
#endif // __ARM_NEON
|
||||||
|
|
||||||
inline constexpr half operator""_h(long double v) {
|
inline constexpr half operator "" _h(long double v) {
|
||||||
return half( static_cast<float>(v) );
|
return half( static_cast<float>(v) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace filament::math {
|
namespace filament {
|
||||||
|
namespace math {
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template<typename T> class TVec2;
|
template<typename T> class TVec2;
|
||||||
@@ -44,8 +45,6 @@ template<typename T> class TMat22;
|
|||||||
template<typename T> class TMat33;
|
template<typename T> class TMat33;
|
||||||
template<typename T> class TMat44;
|
template<typename T> class TMat44;
|
||||||
|
|
||||||
template<typename T> class TQuaternion;
|
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
using double2 = details::TVec2<double>;
|
using double2 = details::TVec2<double>;
|
||||||
@@ -87,10 +86,8 @@ using mat3f = details::TMat33<float>;
|
|||||||
using mat4 = details::TMat44<double>;
|
using mat4 = details::TMat44<double>;
|
||||||
using mat4f = details::TMat44<float>;
|
using mat4f = details::TMat44<float>;
|
||||||
|
|
||||||
using quat = details::TQuaternion<double>;
|
} // namespace math
|
||||||
using quatf = details::TQuaternion<float>;
|
} // namespace filament
|
||||||
|
|
||||||
} // namespace filament::math
|
|
||||||
|
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
namespace filament::math {
|
namespace filament {
|
||||||
|
namespace math {
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -86,15 +89,15 @@ public:
|
|||||||
|
|
||||||
// constructors
|
// constructors
|
||||||
|
|
||||||
// Leaves object uninitialized. Use with caution.
|
// leaves object uninitialized. use with caution.
|
||||||
explicit constexpr TQuaternion(no_init) {}
|
explicit constexpr TQuaternion(no_init) {}
|
||||||
|
|
||||||
// default constructor. sets all values to zero.
|
// default constructor. sets all values to zero.
|
||||||
constexpr TQuaternion() : x(0), y(0), z(0), w(0) {}
|
constexpr TQuaternion() : x(0), y(0), z(0), w(0) {}
|
||||||
|
|
||||||
// Handles implicit conversion to a quat. Must not be explicit.
|
// handles implicit conversion to a quat. must not be explicit.
|
||||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||||
constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {} // NOLINT(google-explicit-constructor)
|
constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {}
|
||||||
|
|
||||||
// initialize from 4 values to w + xi + yj + zk
|
// initialize from 4 values to w + xi + yj + zk
|
||||||
template<typename A, typename B, typename C, typename D,
|
template<typename A, typename B, typename C, typename D,
|
||||||
@@ -172,29 +175,31 @@ typedef details::TQuaternion<float> quatf;
|
|||||||
typedef details::TQuaternion<half> quath;
|
typedef details::TQuaternion<half> quath;
|
||||||
|
|
||||||
constexpr inline quat operator "" _i(long double v) {
|
constexpr inline quat operator "" _i(long double v) {
|
||||||
return { 0.0, double(v), 0.0, 0.0 };
|
return quat(0.0, double(v), 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline quat operator "" _j(long double v) {
|
constexpr inline quat operator "" _j(long double v) {
|
||||||
return { 0.0, 0.0, double(v), 0.0 };
|
return quat(0.0, 0.0, double(v), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline quat operator "" _k(long double v) {
|
constexpr inline quat operator "" _k(long double v) {
|
||||||
return { 0.0, 0.0, 0.0, double(v) };
|
return quat(0.0, 0.0, 0.0, double(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline quat operator "" _i(unsigned long long v) {
|
constexpr inline quat operator "" _i(unsigned long long v) {
|
||||||
return { 0.0, double(v), 0.0, 0.0 };
|
return quat(0.0, double(v), 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline quat operator "" _j(unsigned long long v) {
|
constexpr inline quat operator "" _j(unsigned long long v) {
|
||||||
return { 0.0, 0.0, double(v), 0.0 };
|
return quat(0.0, 0.0, double(v), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline quat operator "" _k(unsigned long long v) {
|
constexpr inline quat operator "" _k(unsigned long long v) {
|
||||||
return { 0.0, 0.0, 0.0, double(v) };
|
return quat(0.0, 0.0, 0.0, double(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace filament::math
|
// ----------------------------------------------------------------------------------------
|
||||||
|
} // namespace math
|
||||||
|
} // namespace filament
|
||||||
|
|
||||||
#endif // TNT_MATH_QUAT_H
|
#endif // TNT_MATH_QUAT_H
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ public:
|
|||||||
* @see CallStack::capture()
|
* @see CallStack::capture()
|
||||||
*/
|
*/
|
||||||
CallStack() = default;
|
CallStack() = default;
|
||||||
|
template <unsigned long N>
|
||||||
|
explicit CallStack(const std::array<intptr_t, N>& symbols)
|
||||||
|
: m_frame_count(N) {
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
m_stack[i] = symbols[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
CallStack(const CallStack&) = default;
|
CallStack(const CallStack&) = default;
|
||||||
~CallStack() = default;
|
~CallStack() = default;
|
||||||
|
|
||||||
@@ -114,12 +121,10 @@ private:
|
|||||||
|
|
||||||
static constexpr size_t NUM_FRAMES = 20;
|
static constexpr size_t NUM_FRAMES = 20;
|
||||||
|
|
||||||
struct StackFrameInfo {
|
using StackFrameInfo = intptr_t;
|
||||||
intptr_t pc;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t m_frame_count = 0;
|
size_t m_frame_count = 0;
|
||||||
StackFrameInfo m_stack[NUM_FRAMES];
|
StackFrameInfo m_stack[NUM_FRAMES] = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ intptr_t CallStack::operator[](size_t index) const {
|
|||||||
#endif
|
#endif
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
return m_stack[index].pc;
|
return m_stack[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CallStack::getFrameCount() const noexcept {
|
size_t CallStack::getFrameCount() const noexcept {
|
||||||
@@ -91,7 +91,7 @@ void CallStack::update_gcc(size_t ignore) noexcept {
|
|||||||
size -= ignore;
|
size -= ignore;
|
||||||
#endif
|
#endif
|
||||||
for (ssize_t i = 0; i < size; i++) {
|
for (ssize_t i = 0; i < size; i++) {
|
||||||
m_stack[i].pc = intptr_t(array[ignore + i]);
|
m_stack[i] = intptr_t(array[ignore + i]);
|
||||||
}
|
}
|
||||||
size--; // the last one seems to always be 0x0
|
size--; // the last one seems to always be 0x0
|
||||||
|
|
||||||
|
|||||||
@@ -362,13 +362,19 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
|||||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
||||||
LightManager::ShadowOptions* out) {
|
LightManager::ShadowOptions* out) {
|
||||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||||
int const size = tokens[i++].size;
|
int size = tokens[i++].size;
|
||||||
math::float3 splitsVector;
|
math::float3 splitsVector;
|
||||||
for (int j = 0; j < size; ++j) {
|
for (int j = 0; j < size; ++j) {
|
||||||
const jsmntok_t tok = tokens[i];
|
const jsmntok_t tok = tokens[i];
|
||||||
CHECK_KEY(tok);
|
CHECK_KEY(tok);
|
||||||
if (compare(tok, jsonChunk, "mapSize") == 0) {
|
if (compare(tok, jsonChunk, "mapSize") == 0) {
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->mapSize);
|
i = parse(tokens, i + 1, jsonChunk, &out->mapSize);
|
||||||
|
} else if (compare(tok, jsonChunk, "stable") == 0) {
|
||||||
|
i = parse(tokens, i + 1, jsonChunk, &out->stable);
|
||||||
|
} else if (compare(tok, jsonChunk, "lispsm") == 0) {
|
||||||
|
i = parse(tokens, i + 1, jsonChunk, &out->lispsm);
|
||||||
|
} else if (compare(tok, jsonChunk, "screenSpaceContactShadows") == 0) {
|
||||||
|
i = parse(tokens, i + 1, jsonChunk, &out->screenSpaceContactShadows);
|
||||||
} else if (compare(tok, jsonChunk, "shadowCascades") == 0) {
|
} else if (compare(tok, jsonChunk, "shadowCascades") == 0) {
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->shadowCascades);
|
i = parse(tokens, i + 1, jsonChunk, &out->shadowCascades);
|
||||||
} else if (compare(tok, jsonChunk, "cascadeSplitPositions") == 0) {
|
} else if (compare(tok, jsonChunk, "cascadeSplitPositions") == 0) {
|
||||||
@@ -376,27 +382,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
|||||||
out->cascadeSplitPositions[0] = splitsVector[0];
|
out->cascadeSplitPositions[0] = splitsVector[0];
|
||||||
out->cascadeSplitPositions[1] = splitsVector[1];
|
out->cascadeSplitPositions[1] = splitsVector[1];
|
||||||
out->cascadeSplitPositions[2] = splitsVector[2];
|
out->cascadeSplitPositions[2] = splitsVector[2];
|
||||||
// TODO: constantBias
|
|
||||||
// TODO: normalBias
|
|
||||||
// TODO: shadowFar
|
|
||||||
// TODO: shadowNearHint
|
|
||||||
// TODO: shadowFarHint
|
|
||||||
} else if (compare(tok, jsonChunk, "stable") == 0) {
|
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->stable);
|
|
||||||
} else if (compare(tok, jsonChunk, "lispsm") == 0) {
|
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->lispsm);
|
|
||||||
// TODO: polygonOffsetConstant
|
|
||||||
// TODO: polygonOffsetSlope
|
|
||||||
} else if (compare(tok, jsonChunk, "screenSpaceContactShadows") == 0) {
|
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->screenSpaceContactShadows);
|
|
||||||
// TODO: stepCount
|
|
||||||
// TODO: maxShadowDistance
|
|
||||||
} else if (compare(tok, jsonChunk, "vsm") == 0) {
|
} else if (compare(tok, jsonChunk, "vsm") == 0) {
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->vsm);
|
i = parse(tokens, i + 1, jsonChunk, &out->vsm);
|
||||||
} else if (compare(tok, jsonChunk, "shadowBulbRadius") == 0) {
|
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->shadowBulbRadius);
|
|
||||||
} else if (compare(tok, jsonChunk, "transform") == 0) {
|
|
||||||
i = parse(tokens, i + 1, jsonChunk, &out->transform.xyzw);
|
|
||||||
} else {
|
} else {
|
||||||
slog.w << "Invalid shadow options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
slog.w << "Invalid shadow options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||||
i = parse(tokens, i + 1);
|
i = parse(tokens, i + 1);
|
||||||
@@ -578,9 +565,11 @@ void applySettings(Engine* engine, const LightSettings& settings, IndirectLight*
|
|||||||
ibl->setRotation(math::mat3f::rotation(settings.iblRotation, math::float3 { 0, 1, 0 }));
|
ibl->setRotation(math::mat3f::rotation(settings.iblRotation, math::float3 { 0, 1, 0 }));
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < sceneLightCount; i++) {
|
for (size_t i = 0; i < sceneLightCount; i++) {
|
||||||
auto const li = lm->getInstance(sceneLights[i]);
|
light = lm->getInstance(sceneLights[i]);
|
||||||
lm->setShadowCaster(li, settings.enableShadows);
|
if (lm->isSpotLight(light)) {
|
||||||
lm->setShadowOptions(li, settings.shadowOptions);
|
lm->setShadowCaster(light, settings.enableShadows);
|
||||||
|
}
|
||||||
|
lm->setShadowOptions(light, settings.shadowOptions);
|
||||||
}
|
}
|
||||||
view->setSoftShadowOptions(settings.softShadowOptions);
|
view->setSoftShadowOptions(settings.softShadowOptions);
|
||||||
}
|
}
|
||||||
@@ -723,20 +712,18 @@ static std::ostream& operator<<(std::ostream& out, const ColorGradingSettings& i
|
|||||||
|
|
||||||
static std::ostream& operator<<(std::ostream& out, const LightManager::ShadowOptions& in) {
|
static std::ostream& operator<<(std::ostream& out, const LightManager::ShadowOptions& in) {
|
||||||
const float* splits = in.cascadeSplitPositions;
|
const float* splits = in.cascadeSplitPositions;
|
||||||
math::float3 const splitsVector = { splits[0], splits[1], splits[2] };
|
math::float3 splitsVector = { splits[0], splits[1], splits[2] };
|
||||||
return out << "{\n"
|
return out << "{\n"
|
||||||
<< "\"vsm\": {\n"
|
<< "\"vsm\": {\n"
|
||||||
<< "\"elvsm\": " << to_string(in.vsm.elvsm) << ",\n"
|
<< "\"elvsm\": " << to_string(in.vsm.elvsm) << ",\n"
|
||||||
<< "\"blurWidth\": " << in.vsm.blurWidth << "\n"
|
<< "\"blurWidth\": " << in.vsm.blurWidth << "\n"
|
||||||
<< "},\n"
|
<< "},\n"
|
||||||
<< "\"mapSize\": " << in.mapSize << ",\n"
|
<< "\"mapSize\": " << in.mapSize << ",\n"
|
||||||
<< "\"shadowCascades\": " << int(in.shadowCascades) << ",\n"
|
|
||||||
<< "\"cascadeSplitPositions\": " << (splitsVector) << "\n"
|
|
||||||
<< "\"stable\": " << to_string(in.stable) << ",\n"
|
<< "\"stable\": " << to_string(in.stable) << ",\n"
|
||||||
<< "\"lispsm\": " << to_string(in.lispsm) << ",\n"
|
<< "\"lispsm\": " << to_string(in.lispsm) << ",\n"
|
||||||
<< "\"screenSpaceContactShadows\": " << to_string(in.screenSpaceContactShadows) << ",\n"
|
<< "\"screenSpaceContactShadows\": " << to_string(in.screenSpaceContactShadows) << ",\n"
|
||||||
<< "\"shadowBulbRadius\": " << in.shadowBulbRadius << ",\n"
|
<< "\"shadowCascades\": " << int(in.shadowCascades) << ",\n"
|
||||||
<< "\"transform\": " << in.transform.xyzw << ",\n"
|
<< "\"cascadeSplitPositions\": " << (splitsVector) << "\n"
|
||||||
<< "}";
|
<< "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -853,14 +853,6 @@ void ViewerGui::updateUserInterface() {
|
|||||||
ImGui::SliderFloat("Halo falloff", &light.sunlightHaloFalloff, 4.0f, 1024.0f);
|
ImGui::SliderFloat("Halo falloff", &light.sunlightHaloFalloff, 4.0f, 1024.0f);
|
||||||
ImGui::SliderFloat("Sun radius", &light.sunlightAngularRadius, 0.1f, 10.0f);
|
ImGui::SliderFloat("Sun radius", &light.sunlightAngularRadius, 0.1f, 10.0f);
|
||||||
ImGuiExt::DirectionWidget("Sun direction", light.sunlightDirection.v);
|
ImGuiExt::DirectionWidget("Sun direction", light.sunlightDirection.v);
|
||||||
|
|
||||||
float3 shadowDirection = light.shadowOptions.transform * light.sunlightDirection;
|
|
||||||
ImGuiExt::DirectionWidget("Shadow direction", shadowDirection.v);
|
|
||||||
light.shadowOptions.transform = normalize(quatf{
|
|
||||||
cross(light.sunlightDirection, shadowDirection),
|
|
||||||
sqrt(length2(light.sunlightDirection) * length2(shadowDirection))
|
|
||||||
+ dot(light.sunlightDirection, shadowDirection)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (ImGui::CollapsingHeader("All lights")) {
|
if (ImGui::CollapsingHeader("All lights")) {
|
||||||
ImGui::Checkbox("Enable shadows", &light.enableShadows);
|
ImGui::Checkbox("Enable shadows", &light.enableShadows);
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ struct App {
|
|||||||
|
|
||||||
bool actualSize = false;
|
bool actualSize = false;
|
||||||
bool originIsFarAway = false;
|
bool originIsFarAway = false;
|
||||||
float originDistance = 6378137; // Earth's radius in [m]
|
|
||||||
|
|
||||||
struct Scene {
|
struct Scene {
|
||||||
Entity groundPlane;
|
Entity groundPlane;
|
||||||
@@ -760,7 +759,6 @@ int main(int argc, char** argv) {
|
|||||||
ImGui::Checkbox("Disable buffer padding", debug.getPropertyAddress<bool>("d.renderer.disable_buffer_padding"));
|
ImGui::Checkbox("Disable buffer padding", debug.getPropertyAddress<bool>("d.renderer.disable_buffer_padding"));
|
||||||
ImGui::Checkbox("Camera at origin", debug.getPropertyAddress<bool>("d.view.camera_at_origin"));
|
ImGui::Checkbox("Camera at origin", debug.getPropertyAddress<bool>("d.view.camera_at_origin"));
|
||||||
ImGui::Checkbox("Far Origin", &app.originIsFarAway);
|
ImGui::Checkbox("Far Origin", &app.originIsFarAway);
|
||||||
ImGui::SliderFloat("Origin", &app.originDistance, 0, 10000000);
|
|
||||||
auto dataSource = debug.getDataSource("d.view.frame_info");
|
auto dataSource = debug.getDataSource("d.view.frame_info");
|
||||||
if (dataSource.data) {
|
if (dataSource.data) {
|
||||||
ImGuiExt::PlotLinesSeries("FrameInfo", 6,
|
ImGuiExt::PlotLinesSeries("FrameInfo", 6,
|
||||||
@@ -958,7 +956,7 @@ int main(int argc, char** argv) {
|
|||||||
tcm.setParent(tcm.getInstance(camera.getEntity()), root);
|
tcm.setParent(tcm.getInstance(camera.getEntity()), root);
|
||||||
tcm.setParent(tcm.getInstance(app.asset->getRoot()), root);
|
tcm.setParent(tcm.getInstance(app.asset->getRoot()), root);
|
||||||
tcm.setParent(tcm.getInstance(view->getFogEntity()), root);
|
tcm.setParent(tcm.getInstance(view->getFogEntity()), root);
|
||||||
tcm.setTransform(root, mat4f::translation(float3{ app.originIsFarAway ? app.originDistance : 0.0f }));
|
tcm.setTransform(root, mat4f::translation(float3{ app.originIsFarAway ? 1e6f : 0.0f }));
|
||||||
|
|
||||||
// Check if color grading has changed.
|
// Check if color grading has changed.
|
||||||
ColorGradingSettings& options = app.viewer->getSettings().view.colorGrading;
|
ColorGradingSettings& options = app.viewer->getSettings().view.colorGrading;
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ highp vec4 getSpotLightSpacePosition(int index, highp vec3 dir, highp float zLig
|
|||||||
// for spotlights, the bias depends on z
|
// for spotlights, the bias depends on z
|
||||||
float bias = shadowUniforms.shadows[index].normalBias * zLight;
|
float bias = shadowUniforms.shadows[index].normalBias * zLight;
|
||||||
|
|
||||||
return computeLightSpacePosition(getWorldPosition(), getWorldGeometricNormalVector(),
|
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
|
||||||
dir, bias, lightFromWorldMatrix);
|
dir, bias, lightFromWorldMatrix);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -141,7 +141,7 @@ highp vec4 getCascadeLightSpacePosition(int cascade) {
|
|||||||
return vertex_lightSpacePosition;
|
return vertex_lightSpacePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
return computeLightSpacePosition(getWorldPosition(), getWorldGeometricNormalVector(),
|
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
|
||||||
frameUniforms.lightDirection,
|
frameUniforms.lightDirection,
|
||||||
shadowUniforms.shadows[cascade].normalBias,
|
shadowUniforms.shadows[cascade].normalBias,
|
||||||
shadowUniforms.shadows[cascade].lightFromWorldMatrix);
|
shadowUniforms.shadows[cascade].lightFromWorldMatrix);
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ end
|
|||||||
|
|
||||||
Then run:
|
Then run:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
pod install
|
$ pod install
|
||||||
```
|
```
|
||||||
|
|
||||||
Close the project and then re-open the newly created HelloCocoaPods.xcworkspace file.
|
Close the project and then re-open the newly created HelloCocoaPods.xcworkspace file.
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.19)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
if(POLICY CMP0077)
|
if(POLICY CMP0077)
|
||||||
cmake_policy(SET CMP0077 NEW) # Enables override of options from parent CMakeLists.txt
|
cmake_policy(SET CMP0077 NEW) # Enables override of options from parent CMakeLists.txt
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.19)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
if (POLICY CMP0048)
|
if (POLICY CMP0048)
|
||||||
cmake_policy(SET CMP0048 NEW)
|
cmake_policy(SET CMP0048 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
# The SPIR-V headers from the SPIR-V Registry
|
# The SPIR-V headers from the SPIR-V Registry
|
||||||
# https://www.khronos.org/registry/spir-v/
|
# https://www.khronos.org/registry/spir-v/
|
||||||
#
|
#
|
||||||
cmake_minimum_required(VERSION 3.19)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(SPIRV-Headers VERSION 1.5.5)
|
project(SPIRV-Headers VERSION 1.5.5)
|
||||||
|
|
||||||
# There are two ways to use this project.
|
# There are two ways to use this project.
|
||||||
|
|||||||
+72
-45
@@ -7,9 +7,9 @@ The tool can consume a HDR environment map in latlong format (equirectilinear) a
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```
|
||||||
cmgen [options] <input-file>
|
$ cmgen [options] <input-file>
|
||||||
cmgen [options] <uv[N]>
|
$ cmgen [options] <uv[N]>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Supported input formats
|
## Supported input formats
|
||||||
@@ -21,45 +21,72 @@ cmgen [options] <uv[N]>
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
```
|
- --license
|
||||||
--help, -h
|
Print copyright and license information
|
||||||
Print this message
|
- --quiet, -q
|
||||||
--license
|
Quiet mode. Suppress all non-error output
|
||||||
Print copyright and license information
|
- --type=[cubemap|equirect|octahedron|ktx], -t [cubemap|equirect|octahedron|ktx]
|
||||||
--quiet, -q
|
Specify output type (default: cubemap)
|
||||||
Quiet mode. Suppress all non-error output
|
- --format=[exr|hdr|psd|rgbm|rgb32f|png|dds|ktx], -f [exr|hdr|psd|rgbm|rgb32f|png|dds|ktx]
|
||||||
--type=[cubemap|equirect|octahedron|ktx], -t [cubemap|equirect|octahedron|ktx]
|
Specify output file format. ktx implies -type=ktx.
|
||||||
Specify output type (default: cubemap)
|
KTX files are always encoded with 3-channel RGB_10_11_11_REV data
|
||||||
--format=[exr|hdr|psd|rgbm|rgb32f|png|dds|ktx], -f [format]
|
- --compression=COMPRESSION, -c COMPRESSION
|
||||||
Specify output file format. ktx implies -type=ktx.
|
Format specific compression:
|
||||||
KTX files are always KTX1 files, not KTX2.
|
KTX:
|
||||||
They are encoded with 3-channel RGB_10_11_11_REV data
|
astc_[fast|thorough]_[ldr|hdr]_WxH, where WxH is a valid block size
|
||||||
--compression=COMPRESSION, -c COMPRESSION
|
s3tc_rgba_dxt5
|
||||||
Format specific compression:
|
etc_FORMAT_METRIC_EFFORT
|
||||||
KTX: ignored
|
FORMAT is rgb8_alpha, srgb8_alpha, rgba8, or srgb8_alpha8
|
||||||
PNG: Ignored
|
METRIC is rgba, rgbx, rec709, numeric, or normalxyz
|
||||||
PNG RGBM: Ignored
|
EFFORT is an integer between 0 and 100
|
||||||
Radiance: Ignored
|
PNG: Ignored
|
||||||
Photoshop: 16 (default), 32
|
PNG RGBM: Ignored
|
||||||
OpenEXR: RAW, RLE, ZIPS, ZIP, PIZ (default)
|
Radiance: Ignored
|
||||||
DDS: 8, 16 (default), 32
|
Photoshop: 16 (default), 32
|
||||||
--size=power-of-two, -s power-of-two
|
OpenEXR: RAW, RLE, ZIPS, ZIP, PIZ (default)
|
||||||
Size of the output cubemaps (base level), 256 by default
|
DDS: 8, 16 (default), 32
|
||||||
Also applies to DFG LUT
|
- --size=power-of-two, -s power-of-two
|
||||||
--deploy=dir, -x dir
|
Size of the output cubemaps (base level), 256 by default
|
||||||
Generate everything needed for deployment into <dir>
|
Also aplies to DFG LUT
|
||||||
--extract=dir
|
- --deploy=dir, -x dir
|
||||||
Extract faces of the cubemap into <dir>
|
Generate everything needed for deployment into <dir>
|
||||||
--extract-blur=roughness
|
- --extract=dir
|
||||||
Blurs the cubemap before saving the faces using the roughness blur
|
Extract faces of the cubemap into <dir>
|
||||||
--clamp
|
- --extract-blur=roughness
|
||||||
Clamp environment before processing
|
Blurs the cubemap before saving the faces using the roughness blur
|
||||||
--no-mirror
|
- --clamp
|
||||||
Skip mirroring of generated cubemaps (for assets with mirroring already backed in)
|
Clamp environment before processing
|
||||||
--ibl-samples=numSamples
|
- --no-mirror
|
||||||
Number of samples to use for IBL integrations (default 1024)
|
Skip mirroring of generated cubemaps (for assets with mirroring already backed in)
|
||||||
--ibl-ld=dir
|
- --ibl-samples=numSamples
|
||||||
Roughness pre-filter into <dir>
|
Number of samples to use for IBL integrations (default 1024)
|
||||||
--sh-shader
|
- --ibl-ld=dir
|
||||||
Generate irradiance SH for shader code
|
Roughness pre-filter into <dir>
|
||||||
```
|
- --sh-shader
|
||||||
|
Generate irradiance SH for shader code
|
||||||
|
|
||||||
|
Private use only:
|
||||||
|
- --ibl-dfg=filename.[exr|hdr|psd|png|rgbm|rgb32f|dds|h|hpp|c|cpp|inc|txt]
|
||||||
|
Compute the IBL DFG LUT
|
||||||
|
- --ibl-dfg-multiscatter
|
||||||
|
If --ibl-dfg is set, computes the DFG for multi-scattering GGX
|
||||||
|
- --ibl-dfg-cloth
|
||||||
|
If --ibl-dfg is set, adds a 3rd channel to the DFG for cloth shading
|
||||||
|
- --ibl-is-mipmap=dir
|
||||||
|
Generate mipmap for pre-filtered importance sampling
|
||||||
|
- --ibl-irradiance=dir
|
||||||
|
Diffuse irradiance into <dir>
|
||||||
|
- --ibl-no-prefilter
|
||||||
|
Use importance sampling instead of prefiltered importance sampling
|
||||||
|
- --ibl-min-lod-size
|
||||||
|
Minimum LOD size [default: 16]
|
||||||
|
- --sh=bands
|
||||||
|
SH decomposition of input cubemap
|
||||||
|
- --sh-output=filename.[exr|hdr|psd|rgbm|rgb32f|png|dds|txt]
|
||||||
|
SH output format. The filename extension determines the output format
|
||||||
|
- --sh-irradiance, -i
|
||||||
|
Irradiance SH coefficients
|
||||||
|
- --sh-window=cutoff|no|auto (default), -w cutoff|no|auto (default)
|
||||||
|
SH windowing to reduce ringing
|
||||||
|
- --debug, -d
|
||||||
|
Generate extra data for debugging
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ identified by an offset and count in the index buffer. Each part can have its ow
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```
|
||||||
filamesh source_mesh destination_mesh
|
$ filamesh source_mesh destination_mesh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Format
|
## Format
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ used for debug purpose only.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```
|
||||||
matinfo [options] <material file>
|
$ matinfo [options] <material file>
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```
|
||||||
mipgen [options] <input_file> <output_pattern>
|
$ mipgen [options] <input_file> <output_pattern>
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `mipgen --help` for more information about available options.
|
Run `mipgen --help` for more information about available options.
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ grazing angles. See Hoffman 2019, "Fresnel Equations Considered Harmful".
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```
|
||||||
specular-color <spectral data file>
|
$ specular-color <spectral data file>
|
||||||
```
|
```
|
||||||
|
|
||||||
The spectral data files can be obtained from
|
The spectral data files can be obtained from
|
||||||
@@ -20,12 +20,12 @@ The spectral data files can be obtained from
|
|||||||
|
|
||||||
For instance, to compute the base color of gold:
|
For instance, to compute the base color of gold:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
specular-color data/gold.txt
|
$ specular-color data/gold.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
To set the second angle, use `-a` to specify the angle in degrees:
|
To set the second angle, use `-a` to specify the angle in degrees:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
specular-color -a 75 data/gold.txt
|
$ specular-color -a 75 data/gold.txt
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -23,26 +23,27 @@ non-compressed variants for each texture, since not all platforms support the sa
|
|||||||
formats. First copy over the PNG files from the [monkey folder], then do:
|
formats. First copy over the PNG files from the [monkey folder], then do:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create mipmaps for base color
|
# Create mipmaps for base color and two compressed variants.
|
||||||
mipgen albedo.png albedo.ktx2
|
mipgen albedo.png albedo.ktx
|
||||||
mipgen --compression=uastc albedo.png albedo.ktx2
|
mipgen --compression=astc_fast_ldr_4x4 albedo.png albedo_astc.ktx
|
||||||
|
mipgen --compression=s3tc_rgb_dxt1 albedo.png albedo_s3tc_srgb.ktx
|
||||||
|
|
||||||
# Create mipmaps for the normal map and a compressed variant.
|
# Create mipmaps for the normal map and a compressed variant.
|
||||||
mipgen --strip-alpha --kernel=NORMALS --linear normal.png normal.ktx
|
mipgen --strip-alpha --kernel=NORMALS --linear normal.png normal.ktx
|
||||||
mipgen --strip-alpha --kernel=NORMALS --linear --compression=uastc_normals \
|
mipgen --strip-alpha --kernel=NORMALS --linear --compression=etc_rgb8_normalxyz_40 \
|
||||||
normal.png normal.ktx2
|
normal.png normal_etc.ktx
|
||||||
|
|
||||||
# Create mipmaps for the single-component roughness map and a compressed variant.
|
# Create mipmaps for the single-component roughness map and a compressed variant.
|
||||||
mipgen --grayscale roughness.png roughness.ktx
|
mipgen --grayscale roughness.png roughness.ktx
|
||||||
mipgen --grayscale --compression=uastc roughness.png roughness.ktx2
|
mipgen --grayscale --compression=etc_r11_numeric_40 roughness.png roughness_etc.ktx
|
||||||
|
|
||||||
# Create mipmaps for the single-component metallic map and a compressed variant.
|
# Create mipmaps for the single-component metallic map and a compressed variant.
|
||||||
mipgen --grayscale metallic.png metallic.ktx
|
mipgen --grayscale metallic.png metallic.ktx
|
||||||
mipgen --grayscale --compression=uastc metallic.png metallic.ktx2
|
mipgen --grayscale --compression=etc_r11_numeric_40 metallic.png metallic_etc.ktx
|
||||||
|
|
||||||
# Create mipmaps for the single-component occlusion map and a compressed variant.
|
# Create mipmaps for the single-component occlusion map and a compressed variant.
|
||||||
mipgen --grayscale ao.png ao.ktx
|
mipgen --grayscale ao.png ao.ktx
|
||||||
mipgen --grayscale --compression=uastc ao.png ao.ktx2
|
mipgen --grayscale --compression=etc_r11_numeric_40 ao.png ao_etc.ktx
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information on mipgen's arguments and supported formats, do `mipgen --help`.
|
For more information on mipgen's arguments and supported formats, do `mipgen --help`.
|
||||||
@@ -236,11 +237,11 @@ was created in the app constructor.
|
|||||||
|
|
||||||
```js {fragment="fetch larger assets"}
|
```js {fragment="fetch larger assets"}
|
||||||
Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => {
|
Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => {
|
||||||
const albedo = this.engine.createTextureFromKtx2(albedo_url, {srgb: true});
|
const albedo = this.engine.createTextureFromKtx1(albedo_url, {srgb: true});
|
||||||
const roughness = this.engine.createTextureFromKtx2(roughness_url);
|
const roughness = this.engine.createTextureFromKtx1(roughness_url);
|
||||||
const metallic = this.engine.createTextureFromKtx2(metallic_url);
|
const metallic = this.engine.createTextureFromKtx1(metallic_url);
|
||||||
const normal = this.engine.createTextureFromKtx2(normal_url);
|
const normal = this.engine.createTextureFromKtx1(normal_url);
|
||||||
const ao = this.engine.createTextureFromKtx2(ao_url);
|
const ao = this.engine.createTextureFromKtx1(ao_url);
|
||||||
|
|
||||||
const sampler = new Filament.TextureSampler(
|
const sampler = new Filament.TextureSampler(
|
||||||
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||||
|
|||||||
@@ -330,9 +330,7 @@ value_object<LightManager::ShadowOptions>("LightManager$ShadowOptions")
|
|||||||
.field("polygonOffsetSlope", &LightManager::ShadowOptions::polygonOffsetSlope)
|
.field("polygonOffsetSlope", &LightManager::ShadowOptions::polygonOffsetSlope)
|
||||||
.field("screenSpaceContactShadows", &LightManager::ShadowOptions::screenSpaceContactShadows)
|
.field("screenSpaceContactShadows", &LightManager::ShadowOptions::screenSpaceContactShadows)
|
||||||
.field("stepCount", &LightManager::ShadowOptions::stepCount)
|
.field("stepCount", &LightManager::ShadowOptions::stepCount)
|
||||||
.field("maxShadowDistance", &LightManager::ShadowOptions::maxShadowDistance)
|
.field("maxShadowDistance", &LightManager::ShadowOptions::maxShadowDistance);
|
||||||
.field("shadowBulbRadius", &LightManager::ShadowOptions::shadowBulbRadius)
|
|
||||||
.field("transform", &LightManager::ShadowOptions::transform);
|
|
||||||
|
|
||||||
// In JavaScript, a flat contiguous representation is best for matrices (see gl-matrix) so we
|
// In JavaScript, a flat contiguous representation is best for matrices (see gl-matrix) so we
|
||||||
// need to define a small wrapper here.
|
// need to define a small wrapper here.
|
||||||
@@ -1339,11 +1337,11 @@ class_<MaterialInstance>("MaterialInstance")
|
|||||||
(MaterialInstance* self, std::string name, filament::math::float4 value), {
|
(MaterialInstance* self, std::string name, filament::math::float4 value), {
|
||||||
self->setParameter(name.c_str(), value); }), allow_raw_pointers())
|
self->setParameter(name.c_str(), value); }), allow_raw_pointers())
|
||||||
.function("setMat3Parameter", EMBIND_LAMBDA(void,
|
.function("setMat3Parameter", EMBIND_LAMBDA(void,
|
||||||
(MaterialInstance* self, std::string name, flatmat3 value), {
|
(MaterialInstance* self, std::string name, filament::math::mat3f value), {
|
||||||
self->setParameter(name.c_str(), value.m); }), allow_raw_pointers())
|
self->setParameter(name.c_str(), value); }), allow_raw_pointers())
|
||||||
.function("setMat4Parameter", EMBIND_LAMBDA(void,
|
.function("setMat4Parameter", EMBIND_LAMBDA(void,
|
||||||
(MaterialInstance* self, std::string name, flatmat4 value), {
|
(MaterialInstance* self, std::string name, filament::math::mat4f value), {
|
||||||
self->setParameter(name.c_str(), value.m); }), allow_raw_pointers())
|
self->setParameter(name.c_str(), value); }), allow_raw_pointers())
|
||||||
.function("setTextureParameter", EMBIND_LAMBDA(void,
|
.function("setTextureParameter", EMBIND_LAMBDA(void,
|
||||||
(MaterialInstance* self, std::string name, Texture* value, TextureSampler sampler), {
|
(MaterialInstance* self, std::string name, Texture* value, TextureSampler sampler), {
|
||||||
self->setParameter(name.c_str(), value, sampler); }), allow_raw_pointers())
|
self->setParameter(name.c_str(), value, sampler); }), allow_raw_pointers())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "filament",
|
"name": "filament",
|
||||||
"version": "1.43.0",
|
"version": "1.42.0",
|
||||||
"description": "Real-time physically based rendering engine",
|
"description": "Real-time physically based rendering engine",
|
||||||
"main": "filament.js",
|
"main": "filament.js",
|
||||||
"module": "filament.js",
|
"module": "filament.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user