Compare commits
193
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7244464a3 | ||
|
|
b066678a37 | ||
|
|
b10d5c58aa | ||
|
|
000bff5ce1 | ||
|
|
47d45a64fa | ||
|
|
2bd48f58ff | ||
|
|
f2f4f556b5 | ||
|
|
5aa15f061b | ||
|
|
63db4f0bf0 | ||
|
|
7797f5af38 | ||
|
|
f9def09d17 | ||
|
|
494934f34e | ||
|
|
caae42fdf6 | ||
|
|
8f6c4841cb | ||
|
|
5d0c06e3f2 | ||
|
|
7d31a7f7ea | ||
|
|
4f4a439f8b | ||
|
|
2306b56ea7 | ||
|
|
eebb40d30d | ||
|
|
766e4f2ec9 | ||
|
|
b0a584c915 | ||
|
|
d5bab43ceb | ||
|
|
485ae1b324 | ||
|
|
75e8961109 | ||
|
|
0e9b2eda0a | ||
|
|
a900bc69fb | ||
|
|
edbfefda0a | ||
|
|
1a0b5ddc14 | ||
|
|
e8bed52b3f | ||
|
|
06e8b1d689 | ||
|
|
9c351b28ab | ||
|
|
cbc3bb3326 | ||
|
|
0eb851ff8c | ||
|
|
038f07cb34 | ||
|
|
62adb234d1 | ||
|
|
53d8d2a41f | ||
|
|
974a69a273 | ||
|
|
7d694ee85e | ||
|
|
46e6664c3d | ||
|
|
4fd7c418e5 | ||
|
|
a3fdca7997 | ||
|
|
7f1704481e | ||
|
|
e6b962b038 | ||
|
|
668fb07ac2 | ||
|
|
f64eef02a3 | ||
|
|
239e98ccec | ||
|
|
919cfae6b2 | ||
|
|
0b9389430b | ||
|
|
1d157677d1 | ||
|
|
ef3f0cb326 | ||
|
|
fcf53f2c3e | ||
|
|
d6fda03b06 | ||
|
|
a76addd2bf | ||
|
|
b1f7731dbe | ||
|
|
e3e12dbf73 | ||
|
|
31a75029f0 | ||
|
|
e5c24cc718 | ||
|
|
2b86c8df6f | ||
|
|
4d8e6eefa1 | ||
|
|
8aeec2ba35 | ||
|
|
4eb4fd5aba | ||
|
|
56355231bd | ||
|
|
9ccb8fce31 | ||
|
|
e674420e9c | ||
|
|
8a9cbcfb99 | ||
|
|
f0d5cd3fa1 | ||
|
|
73b0751ccf | ||
|
|
cc95a4a7a3 | ||
|
|
d76cf643c5 | ||
|
|
6e249c4c1b | ||
|
|
af0c6a7fe9 | ||
|
|
7b7dfad552 | ||
|
|
deb3eb0b11 | ||
|
|
d3016adaff | ||
|
|
6c29542fad | ||
|
|
0d2a96d630 | ||
|
|
d3fe46765f | ||
|
|
892f94e3c4 | ||
|
|
f75f7039f4 | ||
|
|
8303d6b28e | ||
|
|
0f9a2dd6af | ||
|
|
626621fb1c | ||
|
|
2b78fd8359 | ||
|
|
9d181a172a | ||
|
|
d4b9d1e023 | ||
|
|
b62991d967 | ||
|
|
562ea65d5c | ||
|
|
6498cf5b64 | ||
|
|
3c77d2c3f5 | ||
|
|
960c6170fe | ||
|
|
37c2fe31d5 | ||
|
|
21b51caf3d | ||
|
|
76dbc08176 | ||
|
|
1b0db0fca2 | ||
|
|
163f02035f | ||
|
|
14263efbea | ||
|
|
7c6103a458 | ||
|
|
92846305f5 | ||
|
|
d5ebca0c49 | ||
|
|
38ceee8d75 | ||
|
|
fc6744ba75 | ||
|
|
078a17469a | ||
|
|
0887e388db | ||
|
|
e4a57cedf9 | ||
|
|
d92bdce852 | ||
|
|
76bf906856 | ||
|
|
b5e23162df | ||
|
|
eeb53606c8 | ||
|
|
dd23f271e3 | ||
|
|
e78a06797c | ||
|
|
6279613b79 | ||
|
|
78d433cafa | ||
|
|
6590f62052 | ||
|
|
f1f7aeb14f | ||
|
|
5190b03f89 | ||
|
|
2cd492ed38 | ||
|
|
07975868fe | ||
|
|
5ab526cbb0 | ||
|
|
df935b75e5 | ||
|
|
b4d6f975c1 | ||
|
|
2cf86454bb | ||
|
|
5572097fb3 | ||
|
|
480cfb2820 | ||
|
|
39d555d115 | ||
|
|
df50f4c25d | ||
|
|
976f304ee7 | ||
|
|
21ea99a1d9 | ||
|
|
f0b0505207 | ||
|
|
11997d007a | ||
|
|
c0327c95d4 | ||
|
|
e1dfea0f12 | ||
|
|
b2cef9bfee | ||
|
|
f6b979c8e4 | ||
|
|
2e9dd03222 | ||
|
|
9a6b8bf24e | ||
|
|
3aee9402d5 | ||
|
|
fcf5866fc3 | ||
|
|
864a854c13 | ||
|
|
5a18cdf0f6 | ||
|
|
6ebd22f474 | ||
|
|
9f5c1bb0dc | ||
|
|
9cbf741ac2 | ||
|
|
04c8845284 | ||
|
|
d82b7a529c | ||
|
|
72c60b35d7 | ||
|
|
5d30435620 | ||
|
|
d02231dce9 | ||
|
|
ea70fe540f | ||
|
|
cb9bfaeb83 | ||
|
|
3dcdb202d1 | ||
|
|
da73f89a23 | ||
|
|
9474798c75 | ||
|
|
13df6652ae | ||
|
|
4f925f07e8 | ||
|
|
8f64756721 | ||
|
|
9f62dc2f2f | ||
|
|
9c0fb67b87 | ||
|
|
0b97de425f | ||
|
|
373c5710b1 | ||
|
|
91b55bdea1 | ||
|
|
976b8c6ae4 | ||
|
|
c80fbfdf17 | ||
|
|
d4d03e4a35 | ||
|
|
2114995489 | ||
|
|
ec30ddd2fb | ||
|
|
c35a60808c | ||
|
|
58017a0e6a | ||
|
|
d9c2893976 | ||
|
|
1ff0a2dd6d | ||
|
|
da96b45827 | ||
|
|
9ac4fa63ed | ||
|
|
8d621561f3 | ||
|
|
2c63a5ad7a | ||
|
|
d328b64dce | ||
|
|
3ab7780c38 | ||
|
|
6fd5d45295 | ||
|
|
4f11a02889 | ||
|
|
a57225cf2e | ||
|
|
dc818abadc | ||
|
|
c808d8f260 | ||
|
|
e0a37de1ba | ||
|
|
4e2a791e81 | ||
|
|
60627f836f | ||
|
|
22c9d350c1 | ||
|
|
d11a782c3e | ||
|
|
b4a45f126a | ||
|
|
35a8e73675 | ||
|
|
8d7743ce67 | ||
|
|
682585be4a | ||
|
|
9046d04de4 | ||
|
|
0f21c6c90b | ||
|
|
cc6a6454d7 | ||
|
|
609dc97c4a |
@@ -0,0 +1,7 @@
|
|||||||
|
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||||
|
;;; For more information see (info "(emacs) Directory Variables")
|
||||||
|
|
||||||
|
((c++-mode . ((c-file-style . "filament")
|
||||||
|
(apheleia-inhibit . t)))
|
||||||
|
(c-mode . ((c-file-style . "filament")
|
||||||
|
(apheleia-inhibit . t))))
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
[*.{c,cpp,h,inc,kt,java,js,md}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
max_line_length = 100
|
||||||
@@ -29,10 +29,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: filamat-android-full
|
name: filamat-android-full
|
||||||
path: out/filamat-android-release.aar
|
path: out/filamat-android-release.aar
|
||||||
- uses: actions/upload-artifact@v1.0.0
|
|
||||||
with:
|
|
||||||
name: filamat-android-lite
|
|
||||||
path: out/filamat-android-lite-release.aar
|
|
||||||
- uses: actions/upload-artifact@v1.0.0
|
- uses: actions/upload-artifact@v1.0.0
|
||||||
with:
|
with:
|
||||||
name: gltfio-android-release
|
name: gltfio-android-release
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
name: CocoaPods Deploy
|
||||||
|
|
||||||
|
# This must be run after the iOS release job has finished, and the iOS release
|
||||||
|
# asset has been uploaded to Github.
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
description: 'Release tag to deploy (e.g., v1.42.2)'
|
||||||
|
required: true
|
||||||
|
default: 'v1.42.2'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cocoapods-deploy:
|
||||||
|
name: cocoapods-deploy
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out iOS/CocoaPods directory
|
||||||
|
uses: Bhacaz/checkout-files@49fc3050859046bf4f4873678d46099985640e89
|
||||||
|
with:
|
||||||
|
files: ios/CocoaPods
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: ${{ github.event.inputs.release_tag }}
|
||||||
|
- name: Move podspec to root
|
||||||
|
run: mv ios/CocoaPods/*.podspec .
|
||||||
|
- name: Install CocoaPods
|
||||||
|
run: gem install cocoapods
|
||||||
|
- uses: michaelhenry/deploy-to-cocoapods-github-action@745686ab065f90596e0d5cfcf97bb2416d94262e
|
||||||
|
env:
|
||||||
|
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Npm Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
description: 'Release tag to deploy (e.g., v1.42.2)'
|
||||||
|
required: true
|
||||||
|
default: 'v1.42.2'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
npm-deploy:
|
||||||
|
name: npm-deploy
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.3.0
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.release_tag }}
|
||||||
|
# Setup .npmrc file to publish to npm
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- name: Run build script
|
||||||
|
run: |
|
||||||
|
cd build/web && printf "y" | ./build.sh release
|
||||||
|
- name: Deploy to npm
|
||||||
|
run: |
|
||||||
|
cd out/cmake-webgl-release/web/filament-js
|
||||||
|
npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
@@ -124,7 +124,6 @@ jobs:
|
|||||||
cd ../..
|
cd ../..
|
||||||
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
|
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
|
||||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||||
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
|
|
||||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
||||||
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||||
- name: Sign sample-gltf-viewer
|
- name: Sign sample-gltf-viewer
|
||||||
@@ -206,8 +205,7 @@ jobs:
|
|||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
run: |
|
run: |
|
||||||
build\windows\build-github.bat release
|
build\windows\build-github.bat release
|
||||||
cd ..\..
|
move out\filament-windows.tgz out\filament-$Env:TAG-windows.tgz
|
||||||
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
|
|
||||||
shell: cmd
|
shell: cmd
|
||||||
- uses: actions/github-script@v6
|
- uses: actions/github-script@v6
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ settings.json
|
|||||||
test*.png
|
test*.png
|
||||||
test*.json
|
test*.json
|
||||||
results
|
results
|
||||||
|
/compile_commands.json
|
||||||
|
/.cache
|
||||||
|
|||||||
+71
-69
@@ -40,25 +40,27 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If build fails for some reasons, it may leave the `out/` directory in a broken state. You can
|
||||||
|
force a clean build by adding the `-c` flag in that case.
|
||||||
|
|
||||||
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.
|
||||||
You can force a clean build by adding the `-c` flag. The script offers more features described
|
The script offers more features described by executing `build.sh -h`.
|
||||||
by executing `build.sh -h`.
|
|
||||||
|
|
||||||
### Filament-specific CMake Options
|
### Filament-specific CMake Options
|
||||||
|
|
||||||
@@ -76,9 +78,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,20 +104,20 @@ 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 ../..
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -123,17 +125,17 @@ You can also export the `CC` and `CXX` environment variables to always point to
|
|||||||
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 +145,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 +154,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,20 +166,20 @@ $ 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.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
#### Building on Windows with Visual Studio 2019
|
#### Building on Windows with Visual Studio 2019 or later
|
||||||
|
|
||||||
Install the following components:
|
Install the following components:
|
||||||
|
|
||||||
- [Visual Studio 2019](https://www.visualstudio.com/downloads)
|
- [Visual Studio 2019 or later](https://www.visualstudio.com/downloads)
|
||||||
- [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
|
- [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/)
|
||||||
- [Python 3.7](https://www.python.org/ftp/python/3.7.0/python-3.7.0.exe)
|
- [Python 3.7](https://www.python.org/ftp/python/3.7.0/python-3.7.0.exe)
|
||||||
- [CMake 3.14 or later](https://github.com/Kitware/CMake/releases/download/v3.14.7/cmake-3.14.7-win64-x64.msi)
|
- [CMake 3.14 or later](https://github.com/Kitware/CMake/releases/download/v3.14.7/cmake-3.14.7-win64-x64.msi)
|
||||||
|
|
||||||
@@ -191,10 +193,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 +206,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 +239,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 +250,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 +298,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 +313,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 +355,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 +366,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 +376,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 +397,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 +407,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 +429,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 +441,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 +456,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,6 +3,14 @@
|
|||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
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
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -33,6 +41,8 @@ option(FILAMENT_LINUX_IS_MOBILE "Treat Linux as Mobile" OFF)
|
|||||||
|
|
||||||
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
|
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
|
||||||
|
|
||||||
|
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
|
||||||
|
|
||||||
set(FILAMENT_NDK_VERSION "" CACHE STRING
|
set(FILAMENT_NDK_VERSION "" CACHE STRING
|
||||||
"Android NDK version or version prefix to be used when building for Android."
|
"Android NDK version or version prefix to be used when building for Android."
|
||||||
)
|
)
|
||||||
@@ -57,6 +67,9 @@ set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING
|
|||||||
"Size of the Metal handle arena, default 8."
|
"Size of the Metal handle arena, default 8."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Enable exceptions by default in spirv-cross.
|
||||||
|
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF)
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# CMake policies
|
# CMake policies
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -329,6 +342,7 @@ endif()
|
|||||||
|
|
||||||
if (CYGWIN)
|
if (CYGWIN)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||||
|
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
@@ -365,6 +379,7 @@ endif()
|
|||||||
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
|
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
|
||||||
if (ANDROID OR IOS OR WEBGL)
|
if (ANDROID OR IOS OR WEBGL)
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
|
||||||
|
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||||
|
|
||||||
if (ANDROID OR WEBGL)
|
if (ANDROID OR WEBGL)
|
||||||
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
|
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
|
||||||
@@ -376,6 +391,7 @@ endif()
|
|||||||
# std::visit, which is not supported on iOS 11.0 when exceptions are enabled.
|
# std::visit, which is not supported on iOS 11.0 when exceptions are enabled.
|
||||||
if (IOS)
|
if (IOS)
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-exceptions")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-exceptions")
|
||||||
|
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
|
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
|
||||||
@@ -515,6 +531,11 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Disable ESSL 1.0 code generation.
|
||||||
|
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||||
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Enable debug info (preserves names in SPIR-V)
|
# Enable debug info (preserves names in SPIR-V)
|
||||||
if (FILAMENT_ENABLE_MATDBG)
|
if (FILAMENT_ENABLE_MATDBG)
|
||||||
set(MATC_OPT_FLAGS ${MATC_OPT_FLAGS} -d)
|
set(MATC_OPT_FLAGS ${MATC_OPT_FLAGS} -d)
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ again.
|
|||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
See [CodeStyle.md](/CODE_STYLE.md)
|
See [CODE_STYLE.md](/CODE_STYLE.md)
|
||||||
|
|
||||||
## Code reviews
|
## Code reviews
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,3 @@ for next branch cut* header.
|
|||||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||||
|
|
||||||
## Release notes for next branch cut
|
## Release notes for next branch cut
|
||||||
|
|
||||||
- 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.42.0'
|
implementation 'com.google.android.filament:filament-android:1.47.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.42.0'
|
pod 'Filament', '~> 1.47.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Snapshots
|
### Snapshots
|
||||||
|
|||||||
@@ -128,3 +128,15 @@ Navigate to [Filament's release
|
|||||||
workflow](https://github.com/google/filament/actions/workflows/release.yml). Hit the _Run workflow_
|
workflow](https://github.com/google/filament/actions/workflows/release.yml). Hit the _Run workflow_
|
||||||
dropdown. Modify _Platform to build_ and _Release tag to build_, then hit _Run workflow_. This will
|
dropdown. Modify _Platform to build_ and _Release tag to build_, then hit _Run workflow_. This will
|
||||||
initiate a new release run.
|
initiate a new release run.
|
||||||
|
|
||||||
|
## 11. Kick off the npm and CocoaPods release jobs
|
||||||
|
|
||||||
|
Navigate to [Filament's npm deploy
|
||||||
|
workflow](https://github.com/google/filament/actions/workflows/npm-deploy.yml).
|
||||||
|
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
|
||||||
|
release (for example, v1.42.2).
|
||||||
|
|
||||||
|
Navigate to [Filament's CocoaPods deploy
|
||||||
|
workflow](https://github.com/google/filament/actions/workflows/cocopods-deploy.yml).
|
||||||
|
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
|
||||||
|
release (for example, v1.42.2).
|
||||||
|
|||||||
@@ -7,8 +7,79 @@ 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.48.0
|
||||||
|
|
||||||
|
- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
|
||||||
|
- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
|
||||||
|
|
||||||
|
## v1.47.0
|
||||||
|
|
||||||
|
- engine: Support up to 4 side-by-side stereoscopic eyes, configurable at Engine creation time. See
|
||||||
|
`Engine::Config::stereoscopicEyeCount`. [⚠️ **Recompile Materials**]
|
||||||
|
|
||||||
|
## v1.46.0
|
||||||
|
|
||||||
|
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||||
|
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||||
|
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||||
|
- filagui: Add support for feature level 0
|
||||||
|
- matc: Add support for post-process materials in feature level 0
|
||||||
|
- engine: Add `Material::getFeatureLevel()`
|
||||||
|
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||||
|
- engine: Support basic usage of post-processing materials on feature level 0
|
||||||
|
- engine: Fix critical GLES 2.0 bugs
|
||||||
|
- engine: Add `FILAMENT_ENABLE_FEATURE_LEVEL_0` build-time option optionally allow building Filament
|
||||||
|
without FL0 support.
|
||||||
|
|
||||||
|
## v1.45.1
|
||||||
|
|
||||||
|
- engine: Added parameter for configuring JobSystem thread count
|
||||||
|
- engine: In Java, introduce Engine.Builder
|
||||||
|
- gltfio: fix ubershader index for transmission&volume material
|
||||||
|
- engine: New tone mapper: `AgXTonemapper`.
|
||||||
|
- matinfo: Add support for viewing ESSL 1.0 shaders
|
||||||
|
- engine: Add `Renderer::getClearOptions()` [b/243846268]
|
||||||
|
- engine: Fix stable shadows (again) when an IBL rotation is used
|
||||||
|
|
||||||
|
## v1.45.0
|
||||||
|
|
||||||
|
- materials: fix alpha masked materials when MSAA is turned on [⚠️ **Recompile materials**]
|
||||||
|
- materials: better support materials with custom depth [**Recompile Materials**]
|
||||||
|
- engine: fade shadows at shadowFar distance instead of hard cutoff [⚠️ **New Material Version**]
|
||||||
|
|
||||||
|
## v1.44.0
|
||||||
|
|
||||||
|
- engine: add support for skinning with more than four bones per vertex.
|
||||||
|
- engine: remove `BloomOptions::anamorphism` which wasn't working well in most cases [**API CHANGE**]
|
||||||
|
- engine: new API to return a Material's supported variants, C++ only (b/297456590)
|
||||||
|
- build: fix emscripten-1.3.46 build
|
||||||
|
- engine: materials built for feature level 0 can now also be loaded in higher feature levels [⚠️
|
||||||
|
**New Material Version**]
|
||||||
|
|
||||||
|
## v1.43.1
|
||||||
|
|
||||||
|
## 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**]
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
|
|||||||
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
||||||
|
|
||||||
set(FILAMAT_FLAVOR "filamat")
|
set(FILAMAT_FLAVOR "filamat")
|
||||||
if(FILAMAT_LITE)
|
|
||||||
set(FILAMAT_FLAVOR "filamat_lite")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_VULKAN)
|
if (FILAMENT_SUPPORTS_VULKAN)
|
||||||
message("Library filamat ignores Vulkan settings")
|
message("Library filamat ignores Vulkan settings")
|
||||||
|
|||||||
@@ -1,29 +1,8 @@
|
|||||||
android {
|
android {
|
||||||
namespace 'com.google.android.filament.filamat'
|
namespace 'com.google.android.filament.filamat'
|
||||||
|
|
||||||
flavorDimensions "functionality"
|
|
||||||
productFlavors {
|
|
||||||
full {
|
|
||||||
dimension "functionality"
|
|
||||||
}
|
|
||||||
|
|
||||||
lite {
|
|
||||||
dimension "functionality"
|
|
||||||
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
arguments.add("-DFILAMAT_LITE=ON")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
singleVariant("fullRelease") {
|
singleVariant("release") {
|
||||||
withSourcesJar()
|
|
||||||
withJavadocJar()
|
|
||||||
}
|
|
||||||
singleVariant("liteRelease") {
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
@@ -39,14 +18,9 @@ apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
|
|||||||
afterEvaluate { project ->
|
afterEvaluate { project ->
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
fullRelease(MavenPublication) {
|
release(MavenPublication) {
|
||||||
artifactId = POM_ARTIFACT_ID_FULL
|
artifactId = POM_ARTIFACT_ID_FULL
|
||||||
from components.fullRelease
|
from components.release
|
||||||
}
|
|
||||||
|
|
||||||
liteRelease(MavenPublication) {
|
|
||||||
artifactId = POM_ARTIFACT_ID_LITE
|
|
||||||
from components.liteRelease
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,15 +25,8 @@
|
|||||||
using namespace filament;
|
using namespace filament;
|
||||||
using namespace utils;
|
using namespace utils;
|
||||||
|
|
||||||
extern "C" JNIEXPORT jlong JNICALL
|
|
||||||
Java_com_google_android_filament_Engine_nCreateEngine(JNIEnv*, jclass, jlong backend,
|
|
||||||
jlong sharedContext) {
|
|
||||||
return (jlong) Engine::create((Engine::Backend) backend, nullptr, (void*) sharedContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv*, jclass,
|
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv*, jclass, jlong nativeEngine) {
|
||||||
jlong nativeEngine) {
|
|
||||||
Engine* engine = (Engine*) nativeEngine;
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
Engine::destroy(&engine);
|
Engine::destroy(&engine);
|
||||||
}
|
}
|
||||||
@@ -391,6 +384,13 @@ Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
|
|||||||
engine->flushAndWait();
|
engine->flushAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
|
||||||
|
jlong nativeEngine) {
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
engine->flush();
|
||||||
|
}
|
||||||
|
|
||||||
// Managers...
|
// Managers...
|
||||||
|
|
||||||
extern "C" JNIEXPORT jlong JNICALL
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
@@ -435,6 +435,13 @@ Java_com_google_android_filament_Engine_nIsAutomaticInstancingEnabled(JNIEnv*, j
|
|||||||
return (jboolean)engine->isAutomaticInstancingEnabled();
|
return (jboolean)engine->isAutomaticInstancingEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
|
Java_com_google_android_filament_Engine_nGetMaxStereoscopicEyes(JNIEnv*, jclass, jlong nativeEngine) {
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
return (jlong) engine->getMaxStereoscopicEyes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jclass,
|
Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jclass,
|
||||||
jlong nativeEngine) {
|
jlong nativeEngine) {
|
||||||
@@ -455,3 +462,56 @@ Java_com_google_android_filament_Engine_nGetActiveFeatureLevel(JNIEnv *, jclass,
|
|||||||
Engine* engine = (Engine*) nativeEngine;
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
return (jint)engine->getActiveFeatureLevel();
|
return (jint)engine->getActiveFeatureLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_Engine_nCreateBuilder(JNIEnv*,
|
||||||
|
jclass) {
|
||||||
|
Engine::Builder* builder = new Engine::Builder{};
|
||||||
|
return (jlong) builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nDestroyBuilder(JNIEnv*,
|
||||||
|
jclass, jlong nativeBuilder) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
delete builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderBackend(
|
||||||
|
JNIEnv*, jclass, jlong nativeBuilder, jlong backend) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
builder->backend((Engine::Backend) backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderConfig(JNIEnv*,
|
||||||
|
jclass, jlong nativeBuilder, jlong commandBufferSizeMB, jlong perRenderPassArenaSizeMB,
|
||||||
|
jlong driverHandleArenaSizeMB, jlong minCommandBufferSizeMB, jlong perFrameCommandsSizeMB,
|
||||||
|
jlong jobSystemThreadCount, jlong stereoscopicEyeCount) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
Engine::Config config = {
|
||||||
|
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
|
||||||
|
.perRenderPassArenaSizeMB = (uint32_t) perRenderPassArenaSizeMB,
|
||||||
|
.driverHandleArenaSizeMB = (uint32_t) driverHandleArenaSizeMB,
|
||||||
|
.minCommandBufferSizeMB = (uint32_t) minCommandBufferSizeMB,
|
||||||
|
.perFrameCommandsSizeMB = (uint32_t) perFrameCommandsSizeMB,
|
||||||
|
.jobSystemThreadCount = (uint32_t) jobSystemThreadCount,
|
||||||
|
.stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount,
|
||||||
|
};
|
||||||
|
builder->config(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderFeatureLevel(
|
||||||
|
JNIEnv*, jclass, jlong nativeBuilder, jint ordinal) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
builder->featureLevel((Engine::FeatureLevel)ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderSharedContext(
|
||||||
|
JNIEnv*, jclass, jlong nativeBuilder, jlong sharedContext) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
builder->sharedContext((void*) sharedContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
|
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) {
|
||||||
|
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||||
|
return (jlong) builder->build();
|
||||||
|
}
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ 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,
|
||||||
@@ -102,12 +103,18 @@ 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));
|
||||||
for (jsize i = 0; i < splitCount; i++) {
|
std::copy_n(nativeSplits, splitCount, shadowOptions.cascadeSplitPositions);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <filament/Material.h>
|
#include <filament/Material.h>
|
||||||
|
|
||||||
#include "common/NioUtils.h"
|
#include "common/NioUtils.h"
|
||||||
|
#include "common/CallbackUtils.h"
|
||||||
|
|
||||||
using namespace filament;
|
using namespace filament;
|
||||||
|
|
||||||
@@ -105,6 +106,22 @@ Java_com_google_android_filament_Material_nGetRefractionType(JNIEnv*, jclass,
|
|||||||
return (jint) material->getRefractionType();
|
return (jint) material->getRefractionType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_google_android_filament_Material_nGetReflectionMode(JNIEnv*, jclass,
|
||||||
|
jlong nativeMaterial) {
|
||||||
|
Material* material = (Material*) nativeMaterial;
|
||||||
|
return (jint) material->getReflectionMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_google_android_filament_Material_nGetFeatureLevel(JNIEnv*, jclass,
|
||||||
|
jlong nativeMaterial) {
|
||||||
|
Material* material = (Material*) nativeMaterial;
|
||||||
|
return (jint) material->getFeatureLevel();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_com_google_android_filament_Material_nGetVertexDomain(JNIEnv*, jclass,
|
Java_com_google_android_filament_Material_nGetVertexDomain(JNIEnv*, jclass,
|
||||||
@@ -255,3 +272,17 @@ Java_com_google_android_filament_Material_nHasParameter(JNIEnv* env, jclass,
|
|||||||
env->ReleaseStringUTFChars(name_, name);
|
env->ReleaseStringUTFChars(name_, name);
|
||||||
return (jboolean) hasParameter;
|
return (jboolean) hasParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_google_android_filament_Material_nCompile(JNIEnv *env, jclass clazz,
|
||||||
|
jlong nativeMaterial, jint priority, jint variants, jobject handler, jobject runnable) {
|
||||||
|
Material* material = (Material*) nativeMaterial;
|
||||||
|
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
|
||||||
|
material->compile(
|
||||||
|
(Material::CompilerPriorityQueue) priority,
|
||||||
|
(UserVariantFilterBit) variants,
|
||||||
|
jniCallback->getHandler(), [jniCallback](Material*){
|
||||||
|
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ Java_com_google_android_filament_Scene_nRemoveEntities(JNIEnv *env, jclass type,
|
|||||||
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_com_google_android_filament_Scene_nGetEntityCount(JNIEnv *env, jclass type,
|
||||||
|
jlong nativeScene) {
|
||||||
|
Scene* scene = (Scene*) nativeScene;
|
||||||
|
return (jint) scene->getEntityCount();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
Java_com_google_android_filament_Scene_nGetRenderableCount(JNIEnv *env, jclass type,
|
Java_com_google_android_filament_Scene_nGetRenderableCount(JNIEnv *env, jclass type,
|
||||||
jlong nativeScene) {
|
jlong nativeScene) {
|
||||||
@@ -91,3 +98,22 @@ Java_com_google_android_filament_Scene_nHasEntity(JNIEnv *env, jclass type, jlon
|
|||||||
Entity entity = Entity::import(entityId);
|
Entity entity = Entity::import(entityId);
|
||||||
return (jboolean) scene->hasEntity(entity);
|
return (jboolean) scene->hasEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_google_android_filament_Scene_nGetEntities(JNIEnv *env, jclass ,
|
||||||
|
jlong nativeScene, jintArray outArray, jint length) {
|
||||||
|
Scene const* const scene = (Scene*) nativeScene;
|
||||||
|
if (length < scene->getEntityCount()) {
|
||||||
|
// should not happen because we already checked on the java side
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
jint *out = (jint *) env->GetIntArrayElements(outArray, nullptr);
|
||||||
|
scene->forEach([out, length, i = 0](Entity entity)mutable {
|
||||||
|
if (i < length) { // this is just paranoia here
|
||||||
|
out[i++] = (jint) entity.getId();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
env->ReleaseIntArrayElements(outArray, (jint*) out, JNI_ABORT);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ Java_com_google_android_filament_ToneMapper_nCreateFilmicToneMapper(JNIEnv*, jcl
|
|||||||
return (jlong) new FilmicToneMapper();
|
return (jlong) new FilmicToneMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
|
Java_com_google_android_filament_ToneMapper_nCreateAgxToneMapper(JNIEnv*, jclass, jint look) {
|
||||||
|
return (jlong) new AgxToneMapper(AgxToneMapper::AgxLook(look));
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jlong JNICALL
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
Java_com_google_android_filament_ToneMapper_nCreateGenericToneMapper(JNIEnv*, jclass,
|
Java_com_google_android_filament_ToneMapper_nCreateGenericToneMapper(JNIEnv*, jclass,
|
||||||
jfloat contrast, jfloat midGrayIn, jfloat midGrayOut, jfloat hdrMax) {
|
jfloat contrast, jfloat midGrayIn, jfloat midGrayOut, jfloat hdrMax) {
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ Java_com_google_android_filament_View_nSetSSCTOptions(JNIEnv *, jclass, jlong na
|
|||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass,
|
Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass,
|
||||||
jlong nativeView, jlong nativeTexture,
|
jlong nativeView, jlong nativeTexture,
|
||||||
jfloat dirtStrength, jfloat strength, jint resolution, jfloat anamorphism, jint levels,
|
jfloat dirtStrength, jfloat strength, jint resolution, jint levels,
|
||||||
jint blendMode, jboolean threshold, jboolean enabled, jfloat highlight,
|
jint blendMode, jboolean threshold, jboolean enabled, jfloat highlight,
|
||||||
jboolean lensFlare, jboolean starburst, jfloat chromaticAberration, jint ghostCount,
|
jboolean lensFlare, jboolean starburst, jfloat chromaticAberration, jint ghostCount,
|
||||||
jfloat ghostSpacing, jfloat ghostThreshold, jfloat haloThickness, jfloat haloRadius,
|
jfloat ghostSpacing, jfloat ghostThreshold, jfloat haloThickness, jfloat haloRadius,
|
||||||
@@ -294,7 +294,6 @@ Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass,
|
|||||||
.dirtStrength = dirtStrength,
|
.dirtStrength = dirtStrength,
|
||||||
.strength = strength,
|
.strength = strength,
|
||||||
.resolution = (uint32_t)resolution,
|
.resolution = (uint32_t)resolution,
|
||||||
.anamorphism = anamorphism,
|
|
||||||
.levels = (uint8_t)levels,
|
.levels = (uint8_t)levels,
|
||||||
.blendMode = (View::BloomOptions::BlendMode)blendMode,
|
.blendMode = (View::BloomOptions::BlendMode)blendMode,
|
||||||
.threshold = (bool)threshold,
|
.threshold = (bool)threshold,
|
||||||
@@ -481,6 +480,17 @@ Java_com_google_android_filament_View_nIsStencilBufferEnabled(JNIEnv *, jclass,
|
|||||||
return view->isStencilBufferEnabled();
|
return view->isStencilBufferEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_google_android_filament_View_nSetStereoscopicOptions(JNIEnv *, jclass, jlong nativeView,
|
||||||
|
jboolean enabled) {
|
||||||
|
View* view = (View*) nativeView;
|
||||||
|
View::StereoscopicOptions options {
|
||||||
|
.enabled = (bool) enabled
|
||||||
|
};
|
||||||
|
view->setStereoscopicOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
|
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ public class Engine {
|
|||||||
|
|
||||||
private long mNativeObject;
|
private long mNativeObject;
|
||||||
|
|
||||||
|
private Config mConfig;
|
||||||
|
|
||||||
@NonNull private final TransformManager mTransformManager;
|
@NonNull private final TransformManager mTransformManager;
|
||||||
@NonNull private final LightManager mLightManager;
|
@NonNull private final LightManager mLightManager;
|
||||||
@NonNull private final RenderableManager mRenderableManager;
|
@NonNull private final RenderableManager mRenderableManager;
|
||||||
@@ -150,16 +152,219 @@ public class Engine {
|
|||||||
FEATURE_LEVEL_0,
|
FEATURE_LEVEL_0,
|
||||||
/** OpenGL ES 3.0 features (default) */
|
/** OpenGL ES 3.0 features (default) */
|
||||||
FEATURE_LEVEL_1,
|
FEATURE_LEVEL_1,
|
||||||
|
/** OpenGL ES 3.1 features + 16 textures units + cubemap arrays */
|
||||||
|
FEATURE_LEVEL_2,
|
||||||
/** OpenGL ES 3.1 features + 31 textures units + cubemap arrays */
|
/** OpenGL ES 3.1 features + 31 textures units + cubemap arrays */
|
||||||
FEATURE_LEVEL_2
|
FEATURE_LEVEL_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
private Engine(long nativeEngine) {
|
/**
|
||||||
|
* Constructs <code>Engine</code> objects using a builder pattern.
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
|
||||||
|
private final BuilderFinalizer mFinalizer;
|
||||||
|
private final long mNativeBuilder;
|
||||||
|
private Config mConfig;
|
||||||
|
|
||||||
|
public Builder() {
|
||||||
|
mNativeBuilder = nCreateBuilder();
|
||||||
|
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link Backend} for the Engine.
|
||||||
|
*
|
||||||
|
* @param backend Driver backend to use
|
||||||
|
* @return A reference to this Builder for chaining calls.
|
||||||
|
*/
|
||||||
|
public Builder backend(Backend backend) {
|
||||||
|
nSetBuilderBackend(mNativeBuilder, backend.ordinal());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a sharedContext for the Engine.
|
||||||
|
*
|
||||||
|
* @param sharedContext A platform-dependant OpenGL context used as a shared context
|
||||||
|
* when creating filament's internal context. On Android this parameter
|
||||||
|
* <b>must be</b> an instance of {@link android.opengl.EGLContext}.
|
||||||
|
* @return A reference to this Builder for chaining calls.
|
||||||
|
*/
|
||||||
|
public Builder sharedContext(Object sharedContext) {
|
||||||
|
if (Platform.get().validateSharedContext(sharedContext)) {
|
||||||
|
nSetBuilderSharedContext(mNativeBuilder,
|
||||||
|
Platform.get().getSharedContextNativeHandle(sharedContext));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Invalid shared context " + sharedContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the Engine with custom parameters.
|
||||||
|
*
|
||||||
|
* @param config A {@link Config} object
|
||||||
|
* @return A reference to this Builder for chaining calls.
|
||||||
|
*/
|
||||||
|
public Builder config(Config config) {
|
||||||
|
mConfig = config;
|
||||||
|
nSetBuilderConfig(mNativeBuilder, config.commandBufferSizeMB,
|
||||||
|
config.perRenderPassArenaSizeMB, config.driverHandleArenaSizeMB,
|
||||||
|
config.minCommandBufferSizeMB, config.perFrameCommandsSizeMB,
|
||||||
|
config.jobSystemThreadCount, config.stereoscopicEyeCount);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the initial featureLevel for the Engine.
|
||||||
|
*
|
||||||
|
* @param featureLevel The feature level at which initialize Filament.
|
||||||
|
* @return A reference to this Builder for chaining calls.
|
||||||
|
*/
|
||||||
|
public Builder featureLevel(FeatureLevel featureLevel) {
|
||||||
|
nSetBuilderFeatureLevel(mNativeBuilder, featureLevel.ordinal());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of Engine
|
||||||
|
*
|
||||||
|
* @return A newly created <code>Engine</code>, or <code>null</code> if the GPU driver couldn't
|
||||||
|
* be initialized, for instance if it doesn't support the right version of OpenGL or
|
||||||
|
* OpenGL ES.
|
||||||
|
*
|
||||||
|
* @exception IllegalStateException can be thrown if there isn't enough memory to
|
||||||
|
* allocate the command buffer.
|
||||||
|
*/
|
||||||
|
public Engine build() {
|
||||||
|
long nativeEngine = nBuilderBuild(mNativeBuilder);
|
||||||
|
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
|
||||||
|
return new Engine(nativeEngine, mConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BuilderFinalizer {
|
||||||
|
private final long mNativeObject;
|
||||||
|
|
||||||
|
BuilderFinalizer(long nativeObject) {
|
||||||
|
mNativeObject = nativeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finalize() {
|
||||||
|
try {
|
||||||
|
super.finalize();
|
||||||
|
} catch (Throwable t) { // Ignore
|
||||||
|
} finally {
|
||||||
|
nDestroyBuilder(mNativeObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for customizing the initialization of {@link Engine}.
|
||||||
|
*/
|
||||||
|
public static class Config {
|
||||||
|
|
||||||
|
// #defines in Engine.h
|
||||||
|
private static final long FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB = 3;
|
||||||
|
private static final long FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB = 2;
|
||||||
|
private static final long FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB = 1;
|
||||||
|
private static final long FILAMENT_COMMAND_BUFFER_SIZE_IN_MB =
|
||||||
|
FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB * 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in MiB of the low-level command buffer arena.
|
||||||
|
*
|
||||||
|
* Each new command buffer is allocated from here. If this buffer is too small the program
|
||||||
|
* might terminate or rendering errors might occur.
|
||||||
|
*
|
||||||
|
* This is typically set to minCommandBufferSizeMB * 3, so that up to 3 frames can be
|
||||||
|
* batched-up at once.
|
||||||
|
*
|
||||||
|
* This value affects the application's memory usage.
|
||||||
|
*/
|
||||||
|
public long commandBufferSizeMB = FILAMENT_COMMAND_BUFFER_SIZE_IN_MB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in MiB of the per-frame data arena.
|
||||||
|
*
|
||||||
|
* This is the main arena used for allocations when preparing a frame.
|
||||||
|
* e.g.: Froxel data and high-level commands are allocated from this arena.
|
||||||
|
*
|
||||||
|
* If this size is too small, the program will abort on debug builds and have undefined
|
||||||
|
* behavior otherwise.
|
||||||
|
*
|
||||||
|
* This value affects the application's memory usage.
|
||||||
|
*/
|
||||||
|
public long perRenderPassArenaSizeMB = FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in MiB of the backend's handle arena.
|
||||||
|
*
|
||||||
|
* Backends will fallback to slower heap-based allocations when running out of space and
|
||||||
|
* log this condition.
|
||||||
|
*
|
||||||
|
* If 0, then the default value for the given platform is used
|
||||||
|
*
|
||||||
|
* This value affects the application's memory usage.
|
||||||
|
*/
|
||||||
|
public long driverHandleArenaSizeMB = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum size in MiB of a low-level command buffer.
|
||||||
|
*
|
||||||
|
* This is how much space is guaranteed to be available for low-level commands when a new
|
||||||
|
* buffer is allocated. If this is too small, the engine might have to stall to wait for
|
||||||
|
* more space to become available, this situation is logged.
|
||||||
|
*
|
||||||
|
* This value does not affect the application's memory usage.
|
||||||
|
*/
|
||||||
|
public long minCommandBufferSizeMB = FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in MiB of the per-frame high level command buffer.
|
||||||
|
*
|
||||||
|
* This buffer is related to the number of draw calls achievable within a frame, if it is
|
||||||
|
* too small, the program will abort on debug builds and have undefined behavior otherwise.
|
||||||
|
*
|
||||||
|
* It is allocated from the 'per-render-pass arena' above. Make sure that at least 1 MiB is
|
||||||
|
* left in the per-render-pass arena when deciding the size of this buffer.
|
||||||
|
*
|
||||||
|
* This value does not affect the application's memory usage.
|
||||||
|
*/
|
||||||
|
public long perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of threads to use in Engine's JobSystem.
|
||||||
|
*
|
||||||
|
* Engine uses a utils::JobSystem to carry out paralleization of Engine workloads. This
|
||||||
|
* value sets the number of threads allocated for JobSystem. Configuring this value can be
|
||||||
|
* helpful in CPU-constrained environments where too many threads can cause contention of
|
||||||
|
* CPU and reduce performance.
|
||||||
|
*
|
||||||
|
* The default value is 0, which implies that the Engine will use a heuristic to determine
|
||||||
|
* the number of threads to use.
|
||||||
|
*/
|
||||||
|
public long jobSystemThreadCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
|
||||||
|
* between 1 and Engine#getMaxStereoscopicEyes() (inclusive).
|
||||||
|
*
|
||||||
|
* @see View#setStereoscopicOptions
|
||||||
|
* @see Engine#getMaxStereoscopicEyes
|
||||||
|
*/
|
||||||
|
public long stereoscopicEyeCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Engine(long nativeEngine, Config config) {
|
||||||
mNativeObject = nativeEngine;
|
mNativeObject = nativeEngine;
|
||||||
mTransformManager = new TransformManager(nGetTransformManager(nativeEngine));
|
mTransformManager = new TransformManager(nGetTransformManager(nativeEngine));
|
||||||
mLightManager = new LightManager(nGetLightManager(nativeEngine));
|
mLightManager = new LightManager(nGetLightManager(nativeEngine));
|
||||||
mRenderableManager = new RenderableManager(nGetRenderableManager(nativeEngine));
|
mRenderableManager = new RenderableManager(nGetRenderableManager(nativeEngine));
|
||||||
mEntityManager = new EntityManager(nGetEntityManager(nativeEngine));
|
mEntityManager = new EntityManager(nGetEntityManager(nativeEngine));
|
||||||
|
mConfig = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,9 +382,7 @@ public class Engine {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Engine create() {
|
public static Engine create() {
|
||||||
long nativeEngine = nCreateEngine(0, 0);
|
return new Builder().build();
|
||||||
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
|
|
||||||
return new Engine(nativeEngine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,9 +402,9 @@ public class Engine {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Engine create(@NonNull Backend backend) {
|
public static Engine create(@NonNull Backend backend) {
|
||||||
long nativeEngine = nCreateEngine(backend.ordinal(), 0);
|
return new Builder()
|
||||||
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
|
.backend(backend)
|
||||||
return new Engine(nativeEngine);
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,13 +426,9 @@ public class Engine {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Engine create(@NonNull Object sharedContext) {
|
public static Engine create(@NonNull Object sharedContext) {
|
||||||
if (Platform.get().validateSharedContext(sharedContext)) {
|
return new Builder()
|
||||||
long nativeEngine = nCreateEngine(0,
|
.sharedContext(sharedContext)
|
||||||
Platform.get().getSharedContextNativeHandle(sharedContext));
|
.build();
|
||||||
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
|
|
||||||
return new Engine(nativeEngine);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Invalid shared context " + sharedContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,17 +495,23 @@ public class Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate all features of a given feature level. By default FeatureLevel::FEATURE_LEVEL_1 is
|
* Activate all features of a given feature level. If an explicit feature level is not specified
|
||||||
* active. The selected feature level must not be higher than the value returned by
|
* at Engine initialization time via {@link Builder#featureLevel}, the default feature level is
|
||||||
* getActiveFeatureLevel() and it's not possible lower the active feature level.
|
* {@link FeatureLevel#FEATURE_LEVEL_0} on devices not compatible with GLES 3.0; otherwise, the
|
||||||
|
* default is {@link FeatureLevel::FEATURE_LEVEL_1}. The selected feature level must not be
|
||||||
|
* higher than the value returned by {@link #getActiveFeatureLevel} and it's not possible lower
|
||||||
|
* the active feature level. Additionally, it is not possible to modify the feature level at all
|
||||||
|
* if the Engine was initialized at {@link FeatureLevel#FEATURE_LEVEL_0}.
|
||||||
*
|
*
|
||||||
* @param featureLevel the feature level to activate. If featureLevel is lower than
|
* @param featureLevel the feature level to activate. If featureLevel is lower than {@link
|
||||||
* getActiveFeatureLevel(), the current (higher) feature level is kept.
|
* #getActiveFeatureLevel}, the current (higher) feature level is kept. If
|
||||||
* If featureLevel is higher than getSupportedFeatureLevel(), an exception
|
* featureLevel is higher than {@link #getSupportedFeatureLevel}, or if the
|
||||||
* is thrown, or the program is terminated if exceptions are disabled.
|
* engine was initialized at feature level 0, an exception is thrown, or the
|
||||||
|
* program is terminated if exceptions are disabled.
|
||||||
*
|
*
|
||||||
* @return the active feature level.
|
* @return the active feature level.
|
||||||
*
|
*
|
||||||
|
* @see Builder#featureLevel
|
||||||
* @see #getSupportedFeatureLevel
|
* @see #getSupportedFeatureLevel
|
||||||
* @see #getActiveFeatureLevel
|
* @see #getActiveFeatureLevel
|
||||||
*/
|
*/
|
||||||
@@ -352,6 +557,37 @@ public class Engine {
|
|||||||
return nIsAutomaticInstancingEnabled(getNativeObject());
|
return nIsAutomaticInstancingEnabled(getNativeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the configuration settings of this {@link Engine}.
|
||||||
|
*
|
||||||
|
* This method returns the configuration object that was supplied to the Engine's {@link
|
||||||
|
* Builder#config} method during the creation of this Engine. If the {@link Builder::config}
|
||||||
|
* method was not explicitly called (or called with null), this method returns the default
|
||||||
|
* configuration settings.
|
||||||
|
*
|
||||||
|
* @return a {@link Config} object with this Engine's configuration
|
||||||
|
* @see Builder#config
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Config getConfig() {
|
||||||
|
if (mConfig == null) {
|
||||||
|
mConfig = new Config();
|
||||||
|
}
|
||||||
|
return mConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of
|
||||||
|
* eyes rendered is set at Engine creation time with the {@link
|
||||||
|
* Engine#Config#stereoscopicEyeCount} setting.
|
||||||
|
*
|
||||||
|
* @return the max number of stereoscopic eyes supported
|
||||||
|
* @see Engine#Config#stereoscopicEyeCount
|
||||||
|
*/
|
||||||
|
public long getMaxStereoscopicEyes() {
|
||||||
|
return nGetMaxStereoscopicEyes(getNativeObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// SwapChain
|
// SwapChain
|
||||||
|
|
||||||
@@ -888,6 +1124,18 @@ public class Engine {
|
|||||||
nFlushAndWait(getNativeObject());
|
nFlushAndWait(getNativeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait
|
||||||
|
* for commands to be either executed or the hardware finished.
|
||||||
|
*
|
||||||
|
* <p>This is typically used after creating a lot of objects to start draining the command
|
||||||
|
* queue which has a limited size.</p>
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
nFlush(getNativeObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@UsedByReflection("TextureHelper.java")
|
@UsedByReflection("TextureHelper.java")
|
||||||
public long getNativeObject() {
|
public long getNativeObject() {
|
||||||
if (mNativeObject == 0) {
|
if (mNativeObject == 0) {
|
||||||
@@ -914,7 +1162,6 @@ public class Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long nCreateEngine(long backend, long sharedContext);
|
|
||||||
private static native void nDestroyEngine(long nativeEngine);
|
private static native void nDestroyEngine(long nativeEngine);
|
||||||
private static native long nGetBackend(long nativeEngine);
|
private static native long nGetBackend(long nativeEngine);
|
||||||
private static native long nCreateSwapChain(long nativeEngine, Object nativeWindow, long flags);
|
private static native long nCreateSwapChain(long nativeEngine, Object nativeWindow, long flags);
|
||||||
@@ -961,6 +1208,7 @@ public class Engine {
|
|||||||
private static native boolean nIsValidSwapChain(long nativeEngine, long nativeSwapChain);
|
private static native boolean nIsValidSwapChain(long nativeEngine, long nativeSwapChain);
|
||||||
private static native void nDestroyEntity(long nativeEngine, int entity);
|
private static native void nDestroyEntity(long nativeEngine, int entity);
|
||||||
private static native void nFlushAndWait(long nativeEngine);
|
private static native void nFlushAndWait(long nativeEngine);
|
||||||
|
private static native void nFlush(long nativeEngine);
|
||||||
private static native long nGetTransformManager(long nativeEngine);
|
private static native long nGetTransformManager(long nativeEngine);
|
||||||
private static native long nGetLightManager(long nativeEngine);
|
private static native long nGetLightManager(long nativeEngine);
|
||||||
private static native long nGetRenderableManager(long nativeEngine);
|
private static native long nGetRenderableManager(long nativeEngine);
|
||||||
@@ -968,7 +1216,19 @@ public class Engine {
|
|||||||
private static native long nGetEntityManager(long nativeEngine);
|
private static native long nGetEntityManager(long nativeEngine);
|
||||||
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
|
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
|
||||||
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
|
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
|
||||||
|
private static native long nGetMaxStereoscopicEyes(long nativeEngine);
|
||||||
private static native int nGetSupportedFeatureLevel(long nativeEngine);
|
private static native int nGetSupportedFeatureLevel(long nativeEngine);
|
||||||
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
|
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
|
||||||
private static native int nGetActiveFeatureLevel(long nativeEngine);
|
private static native int nGetActiveFeatureLevel(long nativeEngine);
|
||||||
|
|
||||||
|
private static native long nCreateBuilder();
|
||||||
|
private static native void nDestroyBuilder(long nativeBuilder);
|
||||||
|
private static native void nSetBuilderBackend(long nativeBuilder, long backend);
|
||||||
|
private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB,
|
||||||
|
long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB,
|
||||||
|
long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount,
|
||||||
|
long stereoscopicEyeCount);
|
||||||
|
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
|
||||||
|
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
|
||||||
|
private static native long nBuilderBuild(long nativeBuilder);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -258,6 +258,7 @@ 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;
|
||||||
|
|
||||||
@@ -368,6 +369,17 @@ 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 {
|
||||||
@@ -506,7 +518,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.elvsm, options.blurWidth, options.shadowBulbRadius, options.transform);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1169,7 +1181,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);
|
boolean elvsm, float blurWidth, float shadowBulbRadius, float[] transform);
|
||||||
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);
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package com.google.android.filament;
|
|||||||
|
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.Size;
|
import androidx.annotation.Size;
|
||||||
|
|
||||||
import com.google.android.filament.proguard.UsedByNative;
|
import com.google.android.filament.proguard.UsedByNative;
|
||||||
|
import com.google.android.filament.Engine.FeatureLevel;
|
||||||
|
|
||||||
import java.nio.Buffer;
|
import java.nio.Buffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -46,6 +48,8 @@ public class Material {
|
|||||||
static final BlendingMode[] sBlendingModeValues = BlendingMode.values();
|
static final BlendingMode[] sBlendingModeValues = BlendingMode.values();
|
||||||
static final RefractionMode[] sRefractionModeValues = RefractionMode.values();
|
static final RefractionMode[] sRefractionModeValues = RefractionMode.values();
|
||||||
static final RefractionType[] sRefractionTypeValues = RefractionType.values();
|
static final RefractionType[] sRefractionTypeValues = RefractionType.values();
|
||||||
|
static final ReflectionMode[] sReflectionModeValues = ReflectionMode.values();
|
||||||
|
static final FeatureLevel[] sFeatureLevelValues = FeatureLevel.values();
|
||||||
static final VertexDomain[] sVertexDomainValues = VertexDomain.values();
|
static final VertexDomain[] sVertexDomainValues = VertexDomain.values();
|
||||||
static final CullingMode[] sCullingModeValues = CullingMode.values();
|
static final CullingMode[] sCullingModeValues = CullingMode.values();
|
||||||
static final VertexBuffer.VertexAttribute[] sVertexAttributeValues =
|
static final VertexBuffer.VertexAttribute[] sVertexAttributeValues =
|
||||||
@@ -181,6 +185,18 @@ public class Material {
|
|||||||
THIN
|
THIN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported reflection modes
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
|
||||||
|
* Lighting: reflections</a>
|
||||||
|
*/
|
||||||
|
public enum ReflectionMode {
|
||||||
|
DEFAULT,
|
||||||
|
SCREEN_SPACE
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported types of vertex domains
|
* Supported types of vertex domains
|
||||||
*
|
*
|
||||||
@@ -223,6 +239,31 @@ public class Material {
|
|||||||
FRONT_AND_BACK
|
FRONT_AND_BACK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CompilerPriorityQueue {
|
||||||
|
HIGH,
|
||||||
|
LOW
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UserVariantFilterBit {
|
||||||
|
/** Directional lighting */
|
||||||
|
public static int DIRECTIONAL_LIGHTING = 0x01;
|
||||||
|
/** Dynamic lighting */
|
||||||
|
public static int DYNAMIC_LIGHTING = 0x02;
|
||||||
|
/** Shadow receiver */
|
||||||
|
public static int SHADOW_RECEIVER = 0x04;
|
||||||
|
/** Skinning */
|
||||||
|
public static int SKINNING = 0x08;
|
||||||
|
/** Fog */
|
||||||
|
public static int FOG = 0x10;
|
||||||
|
/** Variance shadow maps */
|
||||||
|
public static int VSM = 0x20;
|
||||||
|
/** Screen-space reflections */
|
||||||
|
public static int SSR = 0x40;
|
||||||
|
/** Instanced stereo rendering */
|
||||||
|
public static int STE = 0x80;
|
||||||
|
public static int ALL = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
@UsedByNative("Material.cpp")
|
@UsedByNative("Material.cpp")
|
||||||
public static class Parameter {
|
public static class Parameter {
|
||||||
private static final Type[] sTypeValues = Type.values();
|
private static final Type[] sTypeValues = Type.values();
|
||||||
@@ -337,6 +378,55 @@ public class Material {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously ensures that a subset of this Material's variants are compiled. After issuing
|
||||||
|
* several compile() calls in a row, it is recommended to call {@link Engine#flush}
|
||||||
|
* such that the backend can start the compilation work as soon as possible.
|
||||||
|
* The provided callback is guaranteed to be called on the main thread after all specified
|
||||||
|
* variants of the material are compiled. This can take hundreds of milliseconds.
|
||||||
|
*<p>
|
||||||
|
* If all the material's variants are already compiled, the callback will be scheduled as
|
||||||
|
* soon as possible, but this might take a few dozen millisecond, corresponding to how
|
||||||
|
* many previous frames are enqueued in the backend. This also varies by backend. Therefore,
|
||||||
|
* it is recommended to only call this method once per material shortly after creation.
|
||||||
|
*</p>
|
||||||
|
*<p>
|
||||||
|
* If the same variant is scheduled for compilation multiple times, the first scheduling
|
||||||
|
* takes precedence; later scheduling are ignored.
|
||||||
|
*</p>
|
||||||
|
*<p>
|
||||||
|
* caveat: A consequence is that if a variant is scheduled on the low priority queue and later
|
||||||
|
* scheduled again on the high priority queue, the later scheduling is ignored.
|
||||||
|
* Therefore, the second callback could be called before the variant is compiled.
|
||||||
|
* However, the first callback, if specified, will trigger as expected.
|
||||||
|
*</p>
|
||||||
|
*<p>
|
||||||
|
* The callback is guaranteed to be called. If the engine is destroyed while some material
|
||||||
|
* variants are still compiling or in the queue, these will be discarded and the corresponding
|
||||||
|
* callback will be called. In that case however the Material pointer passed to the callback
|
||||||
|
* is guaranteed to be invalid (either because it's been destroyed by the user already, or,
|
||||||
|
* because it's been cleaned-up by the Engine).
|
||||||
|
*</p>
|
||||||
|
*<p>
|
||||||
|
* {@link UserVariantFilterBit#ALL} should be used with caution. Only variants that an application
|
||||||
|
* needs should be included in the variants argument. For example, the STE variant is only used
|
||||||
|
* for stereoscopic rendering. If an application is not planning to render in stereo, this bit
|
||||||
|
* should be turned off to avoid unnecessary material compilations.
|
||||||
|
*</p>
|
||||||
|
* @param priority Which priority queue to use, LOW or HIGH.
|
||||||
|
* @param variants Variants to include to the compile command.
|
||||||
|
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
|
||||||
|
* @param callback callback called on the main thread when the compilation is done on
|
||||||
|
* by backend.
|
||||||
|
*/
|
||||||
|
public void compile(@NonNull CompilerPriorityQueue priority,
|
||||||
|
int variants,
|
||||||
|
@Nullable Object handler,
|
||||||
|
@Nullable Runnable callback) {
|
||||||
|
nCompile(getNativeObject(), priority.ordinal(), variants, handler, callback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of this material. Material instances should be freed using
|
* Creates a new instance of this material. Material instances should be freed using
|
||||||
* {@link Engine#destroyMaterialInstance(MaterialInstance)}.
|
* {@link Engine#destroyMaterialInstance(MaterialInstance)}.
|
||||||
@@ -437,6 +527,28 @@ public class Material {
|
|||||||
return EnumCache.sRefractionTypeValues[nGetRefractionType(getNativeObject())];
|
return EnumCache.sRefractionTypeValues[nGetRefractionType(getNativeObject())];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reflection mode of this material.
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
|
||||||
|
* Lighting: reflections</a>
|
||||||
|
*/
|
||||||
|
public ReflectionMode getReflectionMode() {
|
||||||
|
return EnumCache.sReflectionModeValues[nGetReflectionMode(getNativeObject())];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum required feature level for this material.
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:featurelevel">
|
||||||
|
* General: featureLevel</a>
|
||||||
|
*/
|
||||||
|
public FeatureLevel getFeatureLevel() {
|
||||||
|
return EnumCache.sFeatureLevelValues[nGetFeatureLevel(getNativeObject())];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the vertex domain of this material.
|
* Returns the vertex domain of this material.
|
||||||
*
|
*
|
||||||
@@ -916,6 +1028,7 @@ public class Material {
|
|||||||
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
||||||
private static native long nGetDefaultInstance(long nativeMaterial);
|
private static native long nGetDefaultInstance(long nativeMaterial);
|
||||||
|
|
||||||
|
private static native void nCompile(long nativeMaterial, int priority, int variants, Object handler, Runnable runnable);
|
||||||
private static native String nGetName(long nativeMaterial);
|
private static native String nGetName(long nativeMaterial);
|
||||||
private static native int nGetShading(long nativeMaterial);
|
private static native int nGetShading(long nativeMaterial);
|
||||||
private static native int nGetInterpolation(long nativeMaterial);
|
private static native int nGetInterpolation(long nativeMaterial);
|
||||||
@@ -932,6 +1045,8 @@ public class Material {
|
|||||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
|
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
|
||||||
private static native int nGetRefractionMode(long nativeMaterial);
|
private static native int nGetRefractionMode(long nativeMaterial);
|
||||||
private static native int nGetRefractionType(long nativeMaterial);
|
private static native int nGetRefractionType(long nativeMaterial);
|
||||||
|
private static native int nGetReflectionMode(long nativeMaterial);
|
||||||
|
private static native int nGetFeatureLevel(long nativeMaterial);
|
||||||
|
|
||||||
|
|
||||||
private static native int nGetParameterCount(long nativeMaterial);
|
private static native int nGetParameterCount(long nativeMaterial);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.google.android.filament;
|
package com.google.android.filament;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,18 +147,29 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of {@link RenderableManager} components in the <code>Scene</code>.
|
* Returns the total number of Entities in the <code>Scene</code>, whether alive or not.
|
||||||
*
|
*
|
||||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>..
|
* @return the total number of Entities in the <code>Scene</code>.
|
||||||
|
*/
|
||||||
|
public int getEntityCount() {
|
||||||
|
return nGetEntityCount(getNativeObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of active (alive) {@link RenderableManager} components in the
|
||||||
|
* <code>Scene</code>.
|
||||||
|
*
|
||||||
|
* @return number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||||
*/
|
*/
|
||||||
public int getRenderableCount() {
|
public int getRenderableCount() {
|
||||||
return nGetRenderableCount(getNativeObject());
|
return nGetRenderableCount(getNativeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of {@link LightManager} components in the <code>Scene</code>.
|
* Returns the number of active (alive) {@link LightManager} components in the
|
||||||
|
* <code>Scene</code>.
|
||||||
*
|
*
|
||||||
* @return number of {@link LightManager} components in the <code>Scene</code>..
|
* @return number of {@link LightManager} components in the <code>Scene</code>.
|
||||||
*/
|
*/
|
||||||
public int getLightCount() {
|
public int getLightCount() {
|
||||||
return nGetLightCount(getNativeObject());
|
return nGetLightCount(getNativeObject());
|
||||||
@@ -179,6 +191,52 @@ public class Scene {
|
|||||||
return mNativeObject;
|
return mNativeObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all entities in the Scene. If outArray is provided and large enough,
|
||||||
|
* it is used to store the list and returned, otherwise a new array is allocated and returned.
|
||||||
|
* @param outArray an array to store the list of entities in the scene.
|
||||||
|
* @return outArray if it was used or a newly allocated array.
|
||||||
|
* @see #getEntityCount
|
||||||
|
*/
|
||||||
|
public int[] getEntities(@Nullable int[] outArray) {
|
||||||
|
int c = getEntityCount();
|
||||||
|
if (outArray == null || outArray.length < c) {
|
||||||
|
outArray = new int[c];
|
||||||
|
}
|
||||||
|
boolean success = nGetEntities(getNativeObject(), outArray, outArray.length);
|
||||||
|
if (!success) {
|
||||||
|
throw new IllegalStateException("Error retriving Scene's entities");
|
||||||
|
}
|
||||||
|
return outArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all entities in the Scene in a newly allocated array.
|
||||||
|
* @return an array containing the list of all entities in the scene.
|
||||||
|
* @see #getEntityCount
|
||||||
|
*/
|
||||||
|
public int[] getEntities() {
|
||||||
|
return getEntities(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface EntityProcessor {
|
||||||
|
void process(@Entity int entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes user functor on each entity in the scene.
|
||||||
|
*
|
||||||
|
* It is not allowed to add or remove an entity from the scene within the functor.
|
||||||
|
*
|
||||||
|
* @param entityProcessor User provided functor called for each entity in the scene
|
||||||
|
*/
|
||||||
|
public void forEach(@NonNull EntityProcessor entityProcessor) {
|
||||||
|
int[] entities = getEntities(null);
|
||||||
|
for (int entity : entities) {
|
||||||
|
entityProcessor.process(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clearNativeObject() {
|
void clearNativeObject() {
|
||||||
mNativeObject = 0;
|
mNativeObject = 0;
|
||||||
}
|
}
|
||||||
@@ -189,7 +247,9 @@ public class Scene {
|
|||||||
private static native void nAddEntities(long nativeScene, int[] entities);
|
private static native void nAddEntities(long nativeScene, int[] entities);
|
||||||
private static native void nRemove(long nativeScene, int entity);
|
private static native void nRemove(long nativeScene, int entity);
|
||||||
private static native void nRemoveEntities(long nativeScene, int[] entities);
|
private static native void nRemoveEntities(long nativeScene, int[] entities);
|
||||||
|
private static native int nGetEntityCount(long nativeScene);
|
||||||
private static native int nGetRenderableCount(long nativeScene);
|
private static native int nGetRenderableCount(long nativeScene);
|
||||||
private static native int nGetLightCount(long nativeScene);
|
private static native int nGetLightCount(long nativeScene);
|
||||||
private static native boolean nHasEntity(long nativeScene, int entity);
|
private static native boolean nHasEntity(long nativeScene, int entity);
|
||||||
|
private static native boolean nGetEntities(long nativeScene, int[] outArray, int length);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,31 @@ public class SwapChain {
|
|||||||
*/
|
*/
|
||||||
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
|
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
|
||||||
|
*
|
||||||
|
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
|
||||||
|
* the SwapChain (when post-processing is disabled).
|
||||||
|
*
|
||||||
|
* The specific format of the stencil buffer depends on platform support. The following pixel
|
||||||
|
* formats are tried, in order of preference:
|
||||||
|
*
|
||||||
|
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
|
||||||
|
* - DEPTH32F
|
||||||
|
* - DEPTH24
|
||||||
|
*
|
||||||
|
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
|
||||||
|
* - DEPTH32F_STENCIL8
|
||||||
|
* - DEPTH24F_STENCIL8
|
||||||
|
*
|
||||||
|
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
|
||||||
|
* necessary.
|
||||||
|
*
|
||||||
|
* @see View#setStencilBufferEnabled
|
||||||
|
* @see View#setPostProcessingEnabled
|
||||||
|
*/
|
||||||
|
public static final long CONFIG_HAS_STENCIL_BUFFER = 0x20;
|
||||||
|
|
||||||
SwapChain(long nativeSwapChain, Object surface) {
|
SwapChain(long nativeSwapChain, Object surface) {
|
||||||
mNativeObject = nativeSwapChain;
|
mNativeObject = nativeSwapChain;
|
||||||
mSurface = surface;
|
mSurface = surface;
|
||||||
|
|||||||
@@ -100,6 +100,45 @@ public class ToneMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AgX tone mapping operator.
|
||||||
|
*/
|
||||||
|
public static class Agx extends ToneMapper {
|
||||||
|
|
||||||
|
public enum AgxLook {
|
||||||
|
/**
|
||||||
|
* Base contrast with no look applied
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A punchy and more chroma laden look for sRGB displays
|
||||||
|
*/
|
||||||
|
PUNCHY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A golden tinted, slightly washed look for BT.1886 displays
|
||||||
|
*/
|
||||||
|
GOLDEN
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a new AgX tone mapper with no look applied.
|
||||||
|
*/
|
||||||
|
public Agx() {
|
||||||
|
this(AgxLook.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a new AgX tone mapper.
|
||||||
|
*
|
||||||
|
* @param look: an optional creative adjustment to contrast and saturation
|
||||||
|
*/
|
||||||
|
public Agx(AgxLook look) {
|
||||||
|
super(nCreateAgxToneMapper(look.ordinal()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic tone mapping operator that gives control over the tone mapping
|
* Generic tone mapping operator that gives control over the tone mapping
|
||||||
* curve. This operator can be used to control the aesthetics of the final
|
* curve. This operator can be used to control the aesthetics of the final
|
||||||
@@ -194,6 +233,7 @@ public class ToneMapper {
|
|||||||
private static native long nCreateACESToneMapper();
|
private static native long nCreateACESToneMapper();
|
||||||
private static native long nCreateACESLegacyToneMapper();
|
private static native long nCreateACESLegacyToneMapper();
|
||||||
private static native long nCreateFilmicToneMapper();
|
private static native long nCreateFilmicToneMapper();
|
||||||
|
private static native long nCreateAgxToneMapper(int look);
|
||||||
private static native long nCreateGenericToneMapper(
|
private static native long nCreateGenericToneMapper(
|
||||||
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
|
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public class View {
|
|||||||
private AmbientOcclusionOptions mAmbientOcclusionOptions;
|
private AmbientOcclusionOptions mAmbientOcclusionOptions;
|
||||||
private BloomOptions mBloomOptions;
|
private BloomOptions mBloomOptions;
|
||||||
private FogOptions mFogOptions;
|
private FogOptions mFogOptions;
|
||||||
|
private StereoscopicOptions mStereoscopicOptions;
|
||||||
private RenderTarget mRenderTarget;
|
private RenderTarget mRenderTarget;
|
||||||
private BlendMode mBlendMode;
|
private BlendMode mBlendMode;
|
||||||
private DepthOfFieldOptions mDepthOfFieldOptions;
|
private DepthOfFieldOptions mDepthOfFieldOptions;
|
||||||
@@ -904,7 +905,7 @@ public class View {
|
|||||||
mBloomOptions = options;
|
mBloomOptions = options;
|
||||||
nSetBloomOptions(getNativeObject(), options.dirt != null ? options.dirt.getNativeObject() : 0,
|
nSetBloomOptions(getNativeObject(), options.dirt != null ? options.dirt.getNativeObject() : 0,
|
||||||
options.dirtStrength, options.strength, options.resolution,
|
options.dirtStrength, options.strength, options.resolution,
|
||||||
options.anamorphism, options.levels, options.blendMode.ordinal(),
|
options.levels, options.blendMode.ordinal(),
|
||||||
options.threshold, options.enabled, options.highlight,
|
options.threshold, options.enabled, options.highlight,
|
||||||
options.lensFlare, options.starburst, options.chromaticAberration,
|
options.lensFlare, options.starburst, options.chromaticAberration,
|
||||||
options.ghostCount, options.ghostSpacing, options.ghostThreshold,
|
options.ghostCount, options.ghostSpacing, options.ghostThreshold,
|
||||||
@@ -1032,7 +1033,8 @@ public class View {
|
|||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Post-processing must be enabled in order to use the stencil buffer.
|
* If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER
|
||||||
|
* flag set in order to use the stencil buffer.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1054,6 +1056,51 @@ public class View {
|
|||||||
return nIsStencilBufferEnabled(getNativeObject());
|
return nIsStencilBufferEnabled(getNativeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the stereoscopic rendering options for this view.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Currently, only one type of stereoscopic rendering is supported: side-by-side.
|
||||||
|
* Side-by-side stereo rendering splits the viewport into two halves: a left and right half.
|
||||||
|
* Eye 0 will render to the left half, while Eye 1 will render into the right half.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Currently, the following features are not supported with stereoscopic rendering:
|
||||||
|
* - post-processing
|
||||||
|
* - shadowing
|
||||||
|
* - punctual lights
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Stereo rendering depends on device and platform support. To check if stereo rendering is
|
||||||
|
* supported, use {@link Engine#isStereoSupported()}. If stereo rendering is not supported, then
|
||||||
|
* the stereoscopic options have no effect.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param options The stereoscopic options to use on this view
|
||||||
|
* @see #getStereoscopicOptions
|
||||||
|
*/
|
||||||
|
public void setStereoscopicOptions(@NonNull StereoscopicOptions options) {
|
||||||
|
mStereoscopicOptions = options;
|
||||||
|
nSetStereoscopicOptions(getNativeObject(), options.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the stereoscopic options.
|
||||||
|
*
|
||||||
|
* @return options Stereoscopic options currently set.
|
||||||
|
* @see #setStereoscopicOptions
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public StereoscopicOptions getStereoscoopicOptions() {
|
||||||
|
if (mStereoscopicOptions == null) {
|
||||||
|
mStereoscopicOptions = new StereoscopicOptions();
|
||||||
|
}
|
||||||
|
return mStereoscopicOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class containing the result of a picking query
|
* A class containing the result of a picking query
|
||||||
*/
|
*/
|
||||||
@@ -1216,9 +1263,10 @@ public class View {
|
|||||||
private static native int nGetAmbientOcclusion(long nativeView);
|
private static native int nGetAmbientOcclusion(long nativeView);
|
||||||
private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, float bilateralThreshold, int quality, int lowPassFilter, int upsampling, boolean enabled, boolean bentNormals, float minHorizonAngleRad);
|
private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, float bilateralThreshold, int quality, int lowPassFilter, int upsampling, boolean enabled, boolean bentNormals, float minHorizonAngleRad);
|
||||||
private static native void nSetSSCTOptions(long nativeView, float ssctLightConeRad, float ssctStartTraceDistance, float ssctContactDistanceMax, float ssctIntensity, float v, float v1, float v2, float ssctDepthBias, float ssctDepthSlopeBias, int ssctSampleCount, int ssctRayCount, boolean ssctEnabled);
|
private static native void nSetSSCTOptions(long nativeView, float ssctLightConeRad, float ssctStartTraceDistance, float ssctContactDistanceMax, float ssctIntensity, float v, float v1, float v2, float ssctDepthBias, float ssctDepthSlopeBias, int ssctSampleCount, int ssctRayCount, boolean ssctEnabled);
|
||||||
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled, float highlight,
|
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, int levels, int blendMode, boolean threshold, boolean enabled, float highlight,
|
||||||
boolean lensFlare, boolean starburst, float chromaticAberration, int ghostCount, float ghostSpacing, float ghostThreshold, float haloThickness, float haloRadius, float haloThreshold);
|
boolean lensFlare, boolean starburst, float chromaticAberration, int ghostCount, float ghostSpacing, float ghostThreshold, float haloThickness, float haloRadius, float haloThreshold);
|
||||||
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, long skyColorNativeObject, boolean enabled);
|
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, long skyColorNativeObject, boolean enabled);
|
||||||
|
private static native void nSetStereoscopicOptions(long nativeView, boolean enabled);
|
||||||
private static native void nSetBlendMode(long nativeView, int blendMode);
|
private static native void nSetBlendMode(long nativeView, int blendMode);
|
||||||
private static native void nSetDepthOfFieldOptions(long nativeView, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
|
private static native void nSetDepthOfFieldOptions(long nativeView, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
|
||||||
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
|
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
|
||||||
@@ -1353,8 +1401,6 @@ public class View {
|
|||||||
* blendMode: Whether the bloom effect is purely additive (false) or mixed with the original
|
* blendMode: Whether the bloom effect is purely additive (false) or mixed with the original
|
||||||
* image (true).
|
* image (true).
|
||||||
*
|
*
|
||||||
* anamorphism: Bloom's aspect ratio (x/y), for artistic purposes.
|
|
||||||
*
|
|
||||||
* threshold: When enabled, a threshold at 1.0 is applied on the source image, this is
|
* threshold: When enabled, a threshold at 1.0 is applied on the source image, this is
|
||||||
* useful for artistic reasons and is usually needed when a dirt texture is used.
|
* useful for artistic reasons and is usually needed when a dirt texture is used.
|
||||||
*
|
*
|
||||||
@@ -1393,10 +1439,6 @@ public class View {
|
|||||||
* resolution of vertical axis (2^levels to 2048)
|
* resolution of vertical axis (2^levels to 2048)
|
||||||
*/
|
*/
|
||||||
public int resolution = 384;
|
public int resolution = 384;
|
||||||
/**
|
|
||||||
* bloom x/y aspect-ratio (1/32 to 32)
|
|
||||||
*/
|
|
||||||
public float anamorphism = 1.0f;
|
|
||||||
/**
|
/**
|
||||||
* number of blur levels (1 to 11)
|
* number of blur levels (1 to 11)
|
||||||
*/
|
*/
|
||||||
@@ -1418,6 +1460,17 @@ public class View {
|
|||||||
* limit highlights to this value before bloom [10, +inf]
|
* limit highlights to this value before bloom [10, +inf]
|
||||||
*/
|
*/
|
||||||
public float highlight = 1000.0f;
|
public float highlight = 1000.0f;
|
||||||
|
/**
|
||||||
|
* Bloom quality level.
|
||||||
|
* LOW (default): use a more optimized down-sampling filter, however there can be artifacts
|
||||||
|
* with dynamic resolution, this can be alleviated by using the homogenous mode.
|
||||||
|
* MEDIUM: Good balance between quality and performance.
|
||||||
|
* HIGH: In this mode the bloom resolution is automatically increased to avoid artifacts.
|
||||||
|
* This mode can be significantly slower on mobile, especially at high resolution.
|
||||||
|
* This mode greatly improves the anamorphic bloom.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public QualityLevel quality = QualityLevel.LOW;
|
||||||
/**
|
/**
|
||||||
* enable screen-space lens flare
|
* enable screen-space lens flare
|
||||||
*/
|
*/
|
||||||
@@ -1924,6 +1977,7 @@ public class View {
|
|||||||
* PCF with soft shadows and contact hardening
|
* PCF with soft shadows and contact hardening
|
||||||
*/
|
*/
|
||||||
PCSS,
|
PCSS,
|
||||||
|
PCFd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+26
-17
@@ -227,9 +227,11 @@ public class UiHelper {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||||
mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height);
|
mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height);
|
||||||
}
|
}
|
||||||
|
if (mRenderCallback != null) {
|
||||||
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
|
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
|
||||||
mRenderCallback.onResized(width, height);
|
mRenderCallback.onResized(width, height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void detach() {
|
public void detach() {
|
||||||
@@ -298,7 +300,6 @@ public class UiHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether we are ready to render into the attached surface.
|
* Checks whether we are ready to render into the attached surface.
|
||||||
*
|
|
||||||
* Using OpenGL ES when this returns true, will result in drawing commands being lost,
|
* Using OpenGL ES when this returns true, will result in drawing commands being lost,
|
||||||
* HOWEVER, GLES state will be preserved. This is useful to initialize the engine.
|
* HOWEVER, GLES state will be preserved. This is useful to initialize the engine.
|
||||||
*
|
*
|
||||||
@@ -343,7 +344,6 @@ public class UiHelper {
|
|||||||
/**
|
/**
|
||||||
* Controls whether the render target (SurfaceView or TextureView) is opaque or not.
|
* Controls whether the render target (SurfaceView or TextureView) is opaque or not.
|
||||||
* The render target is considered opaque by default.
|
* The render target is considered opaque by default.
|
||||||
*
|
|
||||||
* Must be called before calling {@link #attachTo(SurfaceView)}, {@link #attachTo(TextureView)},
|
* Must be called before calling {@link #attachTo(SurfaceView)}, {@link #attachTo(TextureView)},
|
||||||
* or {@link #attachTo(SurfaceHolder)}.
|
* or {@link #attachTo(SurfaceHolder)}.
|
||||||
*
|
*
|
||||||
@@ -366,10 +366,8 @@ public class UiHelper {
|
|||||||
* positioned above other surfaces but below the activity's surface. This property
|
* positioned above other surfaces but below the activity's surface. This property
|
||||||
* only has an effect when used in combination with {@link #setOpaque(boolean) setOpaque(false)}
|
* only has an effect when used in combination with {@link #setOpaque(boolean) setOpaque(false)}
|
||||||
* and does not affect TextureView targets.
|
* and does not affect TextureView targets.
|
||||||
*
|
|
||||||
* Must be called before calling {@link #attachTo(SurfaceView)}
|
* Must be called before calling {@link #attachTo(SurfaceView)}
|
||||||
* or {@link #attachTo(TextureView)}.
|
* or {@link #attachTo(TextureView)}.
|
||||||
*
|
|
||||||
* Has no effect when using {@link #attachTo(SurfaceHolder)}.
|
* Has no effect when using {@link #attachTo(SurfaceHolder)}.
|
||||||
*
|
*
|
||||||
* @param overlay Indicates whether the render target should be rendered below the activity's
|
* @param overlay Indicates whether the render target should be rendered below the activity's
|
||||||
@@ -390,7 +388,6 @@ public class UiHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate UiHelper with a SurfaceView.
|
* Associate UiHelper with a SurfaceView.
|
||||||
*
|
|
||||||
* As soon as SurfaceView is ready (i.e. has a Surface), we'll create the
|
* As soon as SurfaceView is ready (i.e. has a Surface), we'll create the
|
||||||
* EGL resources needed, and call user callbacks if needed.
|
* EGL resources needed, and call user callbacks if needed.
|
||||||
*/
|
*/
|
||||||
@@ -412,21 +409,23 @@ public class UiHelper {
|
|||||||
|
|
||||||
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
||||||
createSwapChain(holder.getSurface());
|
createSwapChain(holder.getSurface());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(
|
public void surfaceChanged(
|
||||||
SurfaceHolder holder, int format, int width, int height) {
|
@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||||
// Note: this is always called at least once after surfaceCreated()
|
// Note: this is always called at least once after surfaceCreated()
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
||||||
|
if (mRenderCallback != null) {
|
||||||
mRenderCallback.onResized(width, height);
|
mRenderCallback.onResized(width, height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
||||||
destroySwapChain();
|
destroySwapChain();
|
||||||
}
|
}
|
||||||
@@ -450,7 +449,6 @@ public class UiHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate UiHelper with a TextureView.
|
* Associate UiHelper with a TextureView.
|
||||||
*
|
|
||||||
* As soon as TextureView is ready (i.e. has a buffer), we'll create the
|
* As soon as TextureView is ready (i.e. has a buffer), we'll create the
|
||||||
* EGL resources needed, and call user callbacks if needed.
|
* EGL resources needed, and call user callbacks if needed.
|
||||||
*/
|
*/
|
||||||
@@ -463,7 +461,7 @@ public class UiHelper {
|
|||||||
TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
|
TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureAvailable(
|
public void onSurfaceTextureAvailable(
|
||||||
SurfaceTexture surfaceTexture, int width, int height) {
|
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureAvailable()");
|
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureAvailable()");
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||||
@@ -478,15 +476,18 @@ public class UiHelper {
|
|||||||
|
|
||||||
createSwapChain(surface);
|
createSwapChain(surface);
|
||||||
|
|
||||||
|
if (mRenderCallback != null) {
|
||||||
// Call this the first time because onSurfaceTextureSizeChanged()
|
// Call this the first time because onSurfaceTextureSizeChanged()
|
||||||
// isn't called at initialization time
|
// isn't called at initialization time
|
||||||
mRenderCallback.onResized(width, height);
|
mRenderCallback.onResized(width, height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureSizeChanged(
|
public void onSurfaceTextureSizeChanged(
|
||||||
SurfaceTexture surfaceTexture, int width, int height) {
|
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureSizeChanged()");
|
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureSizeChanged()");
|
||||||
|
if (mRenderCallback != null) {
|
||||||
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
|
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
|
||||||
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
|
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
|
||||||
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
|
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
|
||||||
@@ -502,16 +503,17 @@ public class UiHelper {
|
|||||||
TextureViewHandler textureViewHandler = (TextureViewHandler) mRenderSurface;
|
TextureViewHandler textureViewHandler = (TextureViewHandler) mRenderSurface;
|
||||||
mRenderCallback.onNativeWindowChanged(textureViewHandler.getSurface());
|
mRenderCallback.onNativeWindowChanged(textureViewHandler.getSurface());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
|
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
|
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
|
||||||
destroySwapChain();
|
destroySwapChain();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
|
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
view.setSurfaceTextureListener(listener);
|
view.setSurfaceTextureListener(listener);
|
||||||
@@ -519,14 +521,15 @@ public class UiHelper {
|
|||||||
// in case the View's SurfaceTexture already existed
|
// in case the View's SurfaceTexture already existed
|
||||||
if (view.isAvailable()) {
|
if (view.isAvailable()) {
|
||||||
SurfaceTexture surfaceTexture = view.getSurfaceTexture();
|
SurfaceTexture surfaceTexture = view.getSurfaceTexture();
|
||||||
|
if (surfaceTexture != null) {
|
||||||
listener.onSurfaceTextureAvailable(surfaceTexture, mDesiredWidth, mDesiredHeight);
|
listener.onSurfaceTextureAvailable(surfaceTexture, mDesiredWidth, mDesiredHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate UiHelper with a SurfaceHolder.
|
* Associate UiHelper with a SurfaceHolder.
|
||||||
*
|
|
||||||
* As soon as a Surface is created, we'll create the
|
* As soon as a Surface is created, we'll create the
|
||||||
* EGL resources needed, and call user callbacks if needed.
|
* EGL resources needed, and call user callbacks if needed.
|
||||||
*/
|
*/
|
||||||
@@ -539,20 +542,22 @@ public class UiHelper {
|
|||||||
|
|
||||||
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder surfaceHolder) {
|
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
||||||
createSwapChain(holder.getSurface());
|
createSwapChain(holder.getSurface());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||||
// Note: this is always called at least once after surfaceCreated()
|
// Note: this is always called at least once after surfaceCreated()
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
||||||
|
if (mRenderCallback != null) {
|
||||||
mRenderCallback.onResized(width, height);
|
mRenderCallback.onResized(width, height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
|
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
|
||||||
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
||||||
destroySwapChain();
|
destroySwapChain();
|
||||||
}
|
}
|
||||||
@@ -587,7 +592,9 @@ public class UiHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createSwapChain(@NonNull Surface surface) {
|
private void createSwapChain(@NonNull Surface surface) {
|
||||||
|
if (mRenderCallback != null) {
|
||||||
mRenderCallback.onNativeWindowChanged(surface);
|
mRenderCallback.onNativeWindowChanged(surface);
|
||||||
|
}
|
||||||
mHasSwapChain = true;
|
mHasSwapChain = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +602,9 @@ public class UiHelper {
|
|||||||
if (mRenderSurface != null) {
|
if (mRenderSurface != null) {
|
||||||
mRenderSurface.detach();
|
mRenderSurface.detach();
|
||||||
}
|
}
|
||||||
|
if (mRenderCallback != null) {
|
||||||
mRenderCallback.onDetachedFromSurface();
|
mRenderCallback.onDetachedFromSurface();
|
||||||
|
}
|
||||||
mHasSwapChain = false;
|
mHasSwapChain = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
missingDimensionStrategy 'functionality', 'full'
|
|
||||||
}
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
// No need to package up the following shared libs, which arise as a side effect of our
|
// No need to package up the following shared libs, which arise as a side effect of our
|
||||||
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
// Operators +, *, / based on http://half.sourceforge.net/ by Christian Rau
|
// Operators +, *, / based on http://half.sourceforge.net/ by Christian Rau
|
||||||
// and licensed under MIT
|
// and licensed under MIT
|
||||||
|
|
||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
package com.google.android.filament.utils
|
package com.google.android.filament.utils
|
||||||
|
|
||||||
import com.google.android.filament.utils.Half.Companion.POSITIVE_INFINITY
|
import com.google.android.filament.utils.Half.Companion.POSITIVE_INFINITY
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ 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
|
||||||
@@ -69,10 +70,12 @@ 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,12 +1,6 @@
|
|||||||
android {
|
android {
|
||||||
namespace 'com.google.android.filament.gltfio'
|
namespace 'com.google.android.filament.gltfio'
|
||||||
|
|
||||||
flavorDimensions "functionality"
|
|
||||||
productFlavors {
|
|
||||||
full {
|
|
||||||
dimension "functionality"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
// No need to package up the following shared libs, which arise as a side effect of our
|
// No need to package up the following shared libs, which arise as a side effect of our
|
||||||
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
||||||
@@ -18,7 +12,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
singleVariant("fullRelease") {
|
singleVariant("release") {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
@@ -36,9 +30,9 @@ apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
|
|||||||
afterEvaluate { project ->
|
afterEvaluate { project ->
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
fullRelease(MavenPublication) {
|
release(MavenPublication) {
|
||||||
artifactId = POM_ARTIFACT_ID_FULL
|
artifactId = POM_ARTIFACT_ID_FULL
|
||||||
from components.fullRelease
|
from components.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.42.0
|
VERSION_NAME=1.47.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,14 +110,24 @@ 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.
|
||||||
|
|
||||||
## Android Studio
|
## Compiling
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ android {
|
|||||||
applicationId "com.google.android.filament.gltf"
|
applicationId "com.google.android.filament.gltf"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion versions.targetSdk
|
targetSdkVersion versions.targetSdk
|
||||||
missingDimensionStrategy 'functionality', 'full'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
||||||
|
|||||||
+31
@@ -26,6 +26,7 @@ import android.widget.TextView
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.google.android.filament.Fence
|
import com.google.android.filament.Fence
|
||||||
import com.google.android.filament.IndirectLight
|
import com.google.android.filament.IndirectLight
|
||||||
|
import com.google.android.filament.Material
|
||||||
import com.google.android.filament.Skybox
|
import com.google.android.filament.Skybox
|
||||||
import com.google.android.filament.View
|
import com.google.android.filament.View
|
||||||
import com.google.android.filament.View.OnPickCallback
|
import com.google.android.filament.View.OnPickCallback
|
||||||
@@ -392,6 +393,36 @@ class MainActivity : Activity() {
|
|||||||
Log.i(TAG, "The Filament backend took $total ms to load the model geometry.")
|
Log.i(TAG, "The Filament backend took $total ms to load the model geometry.")
|
||||||
modelViewer.engine.destroyFence(it)
|
modelViewer.engine.destroyFence(it)
|
||||||
loadStartFence = null
|
loadStartFence = null
|
||||||
|
|
||||||
|
val materials = mutableSetOf<Material>()
|
||||||
|
val rcm = modelViewer.engine.renderableManager
|
||||||
|
modelViewer.scene.forEach {
|
||||||
|
val entity = it
|
||||||
|
if (rcm.hasComponent(entity)) {
|
||||||
|
val ri = rcm.getInstance(entity)
|
||||||
|
val c = rcm.getPrimitiveCount(ri)
|
||||||
|
for (i in 0 until c) {
|
||||||
|
val mi = rcm.getMaterialInstanceAt(ri, i)
|
||||||
|
val ma = mi.material
|
||||||
|
materials.add(ma)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
materials.forEach {
|
||||||
|
it.compile(
|
||||||
|
Material.CompilerPriorityQueue.HIGH,
|
||||||
|
Material.UserVariantFilterBit.DIRECTIONAL_LIGHTING or
|
||||||
|
Material.UserVariantFilterBit.DYNAMIC_LIGHTING or
|
||||||
|
Material.UserVariantFilterBit.SHADOW_RECEIVER,
|
||||||
|
null, null)
|
||||||
|
it.compile(
|
||||||
|
Material.CompilerPriorityQueue.LOW,
|
||||||
|
Material.UserVariantFilterBit.FOG or
|
||||||
|
Material.UserVariantFilterBit.SKINNING or
|
||||||
|
Material.UserVariantFilterBit.SSR or
|
||||||
|
Material.UserVariantFilterBit.VSM,
|
||||||
|
null, null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -20,6 +20,8 @@ import android.animation.ValueAnimator
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.opengl.Matrix
|
import android.opengl.Matrix
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.Choreographer
|
import android.view.Choreographer
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
@@ -110,7 +112,7 @@ class MainActivity : Activity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupFilament() {
|
private fun setupFilament() {
|
||||||
engine = Engine.create()
|
engine = Engine.Builder().featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build()
|
||||||
renderer = engine.createRenderer()
|
renderer = engine.createRenderer()
|
||||||
scene = engine.createScene()
|
scene = engine.createScene()
|
||||||
view = engine.createView()
|
view = engine.createView()
|
||||||
@@ -120,13 +122,8 @@ class MainActivity : Activity() {
|
|||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
||||||
|
|
||||||
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
|
|
||||||
// post-processing is not supported at feature level 0
|
// post-processing is not supported at feature level 0
|
||||||
view.isPostProcessingEnabled = false
|
view.isPostProcessingEnabled = false
|
||||||
} else {
|
|
||||||
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
|
|
||||||
// view.isPostProcessingEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the view which camera we want to use
|
// Tell the view which camera we want to use
|
||||||
view.camera = camera
|
view.camera = camera
|
||||||
@@ -160,12 +157,16 @@ class MainActivity : Activity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadMaterial() {
|
private fun loadMaterial() {
|
||||||
var name = "materials/baked_color.filamat"
|
readUncompressedAsset("materials/baked_color.filamat").let {
|
||||||
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
|
|
||||||
name = "materials/baked_color_es2.filamat"
|
|
||||||
}
|
|
||||||
readUncompressedAsset(name).let {
|
|
||||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||||
|
material.compile(
|
||||||
|
Material.CompilerPriorityQueue.HIGH,
|
||||||
|
Material.UserVariantFilterBit.ALL,
|
||||||
|
Handler(Looper.getMainLooper())) {
|
||||||
|
android.util.Log.i("hellotriangle",
|
||||||
|
"Material " + material.name + " compiled.")
|
||||||
|
}
|
||||||
|
engine.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ material {
|
|||||||
],
|
],
|
||||||
|
|
||||||
// This material disables all lighting
|
// This material disables all lighting
|
||||||
shadingModel : unlit
|
shadingModel : unlit,
|
||||||
|
featureLevel : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment {
|
fragment {
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
// Simple unlit material that uses the colors associated with each vertex.
|
|
||||||
//
|
|
||||||
// This source material must be compiled to a binary material using the matc tool.
|
|
||||||
// The command used to compile this material is:
|
|
||||||
// matc -p mobile -a opengl -o app/src/main/assets/baked_color.filamat app/src/materials/baked_color.mat
|
|
||||||
//
|
|
||||||
// See build.gradle for an example of how to compile materials automatically
|
|
||||||
// Please refer to the documentation for more information about matc and the materials system.
|
|
||||||
|
|
||||||
material {
|
|
||||||
name : baked_color,
|
|
||||||
|
|
||||||
// Lists the required vertex attributes
|
|
||||||
// Here we only need a color (RGBA)
|
|
||||||
requires : [
|
|
||||||
color
|
|
||||||
],
|
|
||||||
|
|
||||||
// This material disables all lighting
|
|
||||||
shadingModel : unlit,
|
|
||||||
featureLevel : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment {
|
|
||||||
void material(inout MaterialInputs material) {
|
|
||||||
// You must always call the prepareMaterial() function
|
|
||||||
prepareMaterial(material);
|
|
||||||
|
|
||||||
// We set the material's color to the color interpolated from
|
|
||||||
// the model's vertices
|
|
||||||
material.baseColor = getColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,13 +32,6 @@ android {
|
|||||||
targetSdkVersion versions.targetSdk
|
targetSdkVersion versions.targetSdk
|
||||||
}
|
}
|
||||||
|
|
||||||
// The filamat library has two variants: full and lite. Here we default to the "full" variant.
|
|
||||||
// Replace "full" with "lite" to use the filamat-lite variant, which has a smaller binary size
|
|
||||||
// but comes with certain restrictions. See "Filamat Lite" in libs/filamat/README.md.
|
|
||||||
defaultConfig {
|
|
||||||
missingDimensionStrategy 'functionality', 'full'
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
||||||
// is not configuration-cache friendly yet; this is only useful for Play publication
|
// is not configuration-cache friendly yet; this is only useful for Play publication
|
||||||
dependenciesInfo {
|
dependenciesInfo {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ android {
|
|||||||
applicationId "com.google.android.filament.textured"
|
applicationId "com.google.android.filament.textured"
|
||||||
minSdkVersion versions.minSdk
|
minSdkVersion versions.minSdk
|
||||||
targetSdkVersion versions.targetSdk
|
targetSdkVersion versions.targetSdk
|
||||||
missingDimensionStrategy 'functionality', 'full'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ function build_clean {
|
|||||||
rm -Rf android/filamat-android/build android/filamat-android/.externalNativeBuild android/filamat-android/.cxx
|
rm -Rf android/filamat-android/build android/filamat-android/.externalNativeBuild android/filamat-android/.cxx
|
||||||
rm -Rf android/gltfio-android/build android/gltfio-android/.externalNativeBuild android/gltfio-android/.cxx
|
rm -Rf android/gltfio-android/build android/gltfio-android/.externalNativeBuild android/gltfio-android/.cxx
|
||||||
rm -Rf android/filament-utils-android/build android/filament-utils-android/.externalNativeBuild android/filament-utils-android/.cxx
|
rm -Rf android/filament-utils-android/build android/filament-utils-android/.externalNativeBuild android/filament-utils-android/.cxx
|
||||||
|
rm -f compile_commands.json
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_clean_aggressive {
|
function build_clean_aggressive {
|
||||||
@@ -210,13 +211,10 @@ 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}"
|
||||||
|
|
||||||
cd "out/cmake-${lc_target}"
|
pushd "out/cmake-${lc_target}" > /dev/null
|
||||||
|
|
||||||
# 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
|
||||||
@@ -233,9 +231,10 @@ function build_desktop_target {
|
|||||||
${MATDBG_OPTION} \
|
${MATDBG_OPTION} \
|
||||||
${MATOPT_OPTION} \
|
${MATOPT_OPTION} \
|
||||||
${ASAN_UBSAN_OPTION} \
|
${ASAN_UBSAN_OPTION} \
|
||||||
${deployment_target} \
|
|
||||||
${architectures} \
|
${architectures} \
|
||||||
../..
|
../..
|
||||||
|
ln -sf "out/cmake-${lc_target}/compile_commands.json" \
|
||||||
|
../../compile_commands.json
|
||||||
fi
|
fi
|
||||||
${BUILD_COMMAND} ${build_targets}
|
${BUILD_COMMAND} ${build_targets}
|
||||||
|
|
||||||
@@ -247,12 +246,13 @@ 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..."
|
||||||
cd "../${lc_target}"
|
pushd "../${lc_target}" > /dev/null
|
||||||
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
|
||||||
|
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_desktop {
|
function build_desktop {
|
||||||
@@ -270,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}"
|
||||||
cd "out/cmake-webgl-${lc_target}"
|
pushd "out/cmake-webgl-${lc_target}" > /dev/null
|
||||||
|
|
||||||
if [[ ! "${BUILD_TARGETS}" ]]; then
|
if [[ ! "${BUILD_TARGETS}" ]]; then
|
||||||
BUILD_TARGETS=${BUILD_CUSTOM_TARGETS}
|
BUILD_TARGETS=${BUILD_CUSTOM_TARGETS}
|
||||||
@@ -290,6 +290,8 @@ function build_webgl_with_target {
|
|||||||
-DCMAKE_INSTALL_PREFIX="../webgl-${lc_target}/filament" \
|
-DCMAKE_INSTALL_PREFIX="../webgl-${lc_target}/filament" \
|
||||||
-DWEBGL=1 \
|
-DWEBGL=1 \
|
||||||
../..
|
../..
|
||||||
|
ln -sf "out/cmake-webgl-${lc_target}/compile_commands.json" \
|
||||||
|
../../compile_commands.json
|
||||||
${BUILD_COMMAND} ${BUILD_TARGETS}
|
${BUILD_COMMAND} ${BUILD_TARGETS}
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
@@ -307,17 +309,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..."
|
||||||
cd web/filament-js
|
pushd web/filament-js > /dev/null
|
||||||
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
|
||||||
cd -
|
popd > /dev/null
|
||||||
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
|
||||||
|
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_webgl {
|
function build_webgl {
|
||||||
@@ -348,7 +350,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}"
|
||||||
|
|
||||||
cd "out/cmake-android-${lc_target}-${arch}"
|
pushd "out/cmake-android-${lc_target}-${arch}" > /dev/null
|
||||||
|
|
||||||
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
||||||
cmake \
|
cmake \
|
||||||
@@ -362,12 +364,14 @@ function build_android_target {
|
|||||||
${MATOPT_OPTION} \
|
${MATOPT_OPTION} \
|
||||||
${VULKAN_ANDROID_OPTION} \
|
${VULKAN_ANDROID_OPTION} \
|
||||||
../..
|
../..
|
||||||
|
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
|
||||||
|
../../compile_commands.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_android_arch {
|
function build_android_arch {
|
||||||
@@ -388,9 +392,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..."
|
||||||
cd "out/android-${lc_target}"
|
pushd "out/android-${lc_target}" > /dev/null
|
||||||
tar -czvf "../filament-android-${lc_target}-${LC_UNAME}.tgz" filament
|
tar -czvf "../filament-android-${lc_target}-${LC_UNAME}.tgz" filament
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -468,7 +472,7 @@ function build_android {
|
|||||||
archive_android "Release"
|
archive_android "Release"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd android
|
pushd android > /dev/null
|
||||||
|
|
||||||
if [[ "${ISSUE_DEBUG_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_DEBUG_BUILD}" == "true" ]]; then
|
||||||
./gradlew \
|
./gradlew \
|
||||||
@@ -498,13 +502,13 @@ function build_android {
|
|||||||
|
|
||||||
if [[ "${INSTALL_COMMAND}" ]]; then
|
if [[ "${INSTALL_COMMAND}" ]]; then
|
||||||
echo "Installing out/filamat-android-debug.aar..."
|
echo "Installing out/filamat-android-debug.aar..."
|
||||||
cp filamat-android/build/outputs/aar/filamat-android-full-debug.aar ../out/filamat-android-debug.aar
|
cp filamat-android/build/outputs/aar/filamat-android-debug.aar ../out/filamat-android-debug.aar
|
||||||
|
|
||||||
echo "Installing out/filament-android-debug.aar..."
|
echo "Installing out/filament-android-debug.aar..."
|
||||||
cp filament-android/build/outputs/aar/filament-android-debug.aar ../out/
|
cp filament-android/build/outputs/aar/filament-android-debug.aar ../out/
|
||||||
|
|
||||||
echo "Installing out/gltfio-android-debug.aar..."
|
echo "Installing out/gltfio-android-debug.aar..."
|
||||||
cp gltfio-android/build/outputs/aar/gltfio-android-full-debug.aar ../out/gltfio-android-debug.aar
|
cp gltfio-android/build/outputs/aar/gltfio-android-debug.aar ../out/gltfio-android-debug.aar
|
||||||
|
|
||||||
echo "Installing out/filament-utils-android-debug.aar..."
|
echo "Installing out/filament-utils-android-debug.aar..."
|
||||||
cp filament-utils-android/build/outputs/aar/filament-utils-android-debug.aar ../out/filament-utils-android-debug.aar
|
cp filament-utils-android/build/outputs/aar/filament-utils-android-debug.aar ../out/filament-utils-android-debug.aar
|
||||||
@@ -547,14 +551,13 @@ function build_android {
|
|||||||
|
|
||||||
if [[ "${INSTALL_COMMAND}" ]]; then
|
if [[ "${INSTALL_COMMAND}" ]]; then
|
||||||
echo "Installing out/filamat-android-release.aar..."
|
echo "Installing out/filamat-android-release.aar..."
|
||||||
cp filamat-android/build/outputs/aar/filamat-android-lite-release.aar ../out/
|
cp filamat-android/build/outputs/aar/filamat-android-release.aar ../out/filamat-android-release.aar
|
||||||
cp filamat-android/build/outputs/aar/filamat-android-full-release.aar ../out/filamat-android-release.aar
|
|
||||||
|
|
||||||
echo "Installing out/filament-android-release.aar..."
|
echo "Installing out/filament-android-release.aar..."
|
||||||
cp filament-android/build/outputs/aar/filament-android-release.aar ../out/
|
cp filament-android/build/outputs/aar/filament-android-release.aar ../out/
|
||||||
|
|
||||||
echo "Installing out/gltfio-android-release.aar..."
|
echo "Installing out/gltfio-android-release.aar..."
|
||||||
cp gltfio-android/build/outputs/aar/gltfio-android-full-release.aar ../out/gltfio-android-release.aar
|
cp gltfio-android/build/outputs/aar/gltfio-android-release.aar ../out/gltfio-android-release.aar
|
||||||
|
|
||||||
echo "Installing out/filament-utils-android-release.aar..."
|
echo "Installing out/filament-utils-android-release.aar..."
|
||||||
cp filament-utils-android/build/outputs/aar/filament-utils-android-release.aar ../out/filament-utils-android-release.aar
|
cp filament-utils-android/build/outputs/aar/filament-utils-android-release.aar ../out/filament-utils-android-release.aar
|
||||||
@@ -569,7 +572,7 @@ function build_android {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd ..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_ios_target {
|
function build_ios_target {
|
||||||
@@ -580,7 +583,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}"
|
||||||
|
|
||||||
cd "out/cmake-ios-${lc_target}-${arch}"
|
pushd "out/cmake-ios-${lc_target}-${arch}" > /dev/null
|
||||||
|
|
||||||
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
|
||||||
cmake \
|
cmake \
|
||||||
@@ -595,6 +598,8 @@ function build_ios_target {
|
|||||||
${MATDBG_OPTION} \
|
${MATDBG_OPTION} \
|
||||||
${MATOPT_OPTION} \
|
${MATOPT_OPTION} \
|
||||||
../..
|
../..
|
||||||
|
ln -sf "out/cmake-ios-${lc_target}-${arch}/compile_commands.json" \
|
||||||
|
../../compile_commands.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${BUILD_COMMAND}
|
${BUILD_COMMAND}
|
||||||
@@ -604,7 +609,7 @@ function build_ios_target {
|
|||||||
${BUILD_COMMAND} ${INSTALL_COMMAND}
|
${BUILD_COMMAND} ${INSTALL_COMMAND}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function archive_ios {
|
function archive_ios {
|
||||||
@@ -613,9 +618,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..."
|
||||||
cd "out/ios-${lc_target}"
|
pushd "out/ios-${lc_target}" > /dev/null
|
||||||
tar -czvf "../filament-${lc_target}-ios.tgz" filament
|
tar -czvf "../filament-${lc_target}-ios.tgz" filament
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -674,14 +679,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
|
||||||
cd out/web-docs
|
pushd out/web-docs > /dev/null
|
||||||
|
|
||||||
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/
|
||||||
|
|
||||||
cd ../..
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate_build_command {
|
function validate_build_command {
|
||||||
@@ -754,6 +759,19 @@ function run_tests {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_debug_release_build {
|
||||||
|
if [[ "${ISSUE_DEBUG_BUILD}" == "true" || \
|
||||||
|
"${ISSUE_RELEASE_BUILD}" == "true" || \
|
||||||
|
"${ISSUE_CLEAN}" == "true" || \
|
||||||
|
"${ISSUE_WEB_DOCS}" == "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
|
||||||
@@ -762,7 +780,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
|||||||
case ${opt} in
|
case ${opt} in
|
||||||
h)
|
h)
|
||||||
print_help
|
print_help
|
||||||
exit 1
|
exit 0
|
||||||
;;
|
;;
|
||||||
a)
|
a)
|
||||||
ISSUE_ARCHIVES=true
|
ISSUE_ARCHIVES=true
|
||||||
@@ -798,7 +816,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 ${platform} in
|
case $(echo "${platform}" | tr '[:upper:]' '[:lower:]') in
|
||||||
desktop)
|
desktop)
|
||||||
ISSUE_DESKTOP_BUILD=true
|
ISSUE_DESKTOP_BUILD=true
|
||||||
;;
|
;;
|
||||||
@@ -817,6 +835,12 @@ 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
|
||||||
;;
|
;;
|
||||||
@@ -829,7 +853,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 ${abi} in
|
case $(echo "${abi}" | tr '[:upper:]' '[:lower:]') in
|
||||||
armeabi-v7a)
|
armeabi-v7a)
|
||||||
ABI_ARMEABI_V7A=true
|
ABI_ARMEABI_V7A=true
|
||||||
;;
|
;;
|
||||||
@@ -848,6 +872,12 @@ 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
|
||||||
;;
|
;;
|
||||||
@@ -911,9 +941,9 @@ fi
|
|||||||
shift $((OPTIND - 1))
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
for arg; do
|
for arg; do
|
||||||
if [[ "${arg}" == "release" ]]; then
|
if [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "release" ]]; then
|
||||||
ISSUE_RELEASE_BUILD=true
|
ISSUE_RELEASE_BUILD=true
|
||||||
elif [[ "${arg}" == "debug" ]]; then
|
elif [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "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}"
|
||||||
@@ -931,19 +961,19 @@ if [[ "${ISSUE_CLEAN_AGGRESSIVE}" == "true" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_DESKTOP_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_DESKTOP_BUILD}" == "true" ]]; then
|
||||||
build_desktop
|
check_debug_release_build build_desktop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_ANDROID_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_ANDROID_BUILD}" == "true" ]]; then
|
||||||
build_android
|
check_debug_release_build build_android
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_IOS_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_IOS_BUILD}" == "true" ]]; then
|
||||||
build_ios
|
check_debug_release_build build_ios
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_WEBGL_BUILD}" == "true" ]]; then
|
if [[ "${ISSUE_WEBGL_BUILD}" == "true" ]]; then
|
||||||
build_webgl
|
check_debug_release_build build_webgl
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${ISSUE_WEB_DOCS}" == "true" ]]; then
|
if [[ "${ISSUE_WEB_DOCS}" == "true" ]]; then
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ libs/math/test_math
|
|||||||
libs/image/test_image compare libs/image/tests/reference/
|
libs/image/test_image compare libs/image/tests/reference/
|
||||||
libs/utils/test_utils
|
libs/utils/test_utils
|
||||||
libs/filamat/test_filamat
|
libs/filamat/test_filamat
|
||||||
libs/filamat/test_filamat_lite
|
|
||||||
tools/matc/test_matc
|
tools/matc/test_matc
|
||||||
tools/cmgen/test_cmgen compare
|
tools/cmgen/test_cmgen compare
|
||||||
tools/glslminifier/test_glslminifier
|
tools/glslminifier/test_glslminifier
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// If you are bundling this with rollup, webpack, or esbuild, the following URL should be trimmed.
|
// If you are bundling this with rollup, webpack, or esbuild, the following URL should be trimmed.
|
||||||
import { LitElement, html, css } from "https://unpkg.com/lit?module";
|
import { LitElement, html, css } from "https://unpkg.com/lit@2.8.0?module";
|
||||||
|
|
||||||
// This little utility checks if the Filament module is ready for action.
|
// This little utility checks if the Filament module is ready for action.
|
||||||
// If so, it immediately calls the given function. If not, it asks the Filament
|
// If so, it immediately calls the given function. If not, it asks the Filament
|
||||||
@@ -287,12 +287,12 @@ class FilamentViewer extends LitElement {
|
|||||||
// Dropping a glb file is simple because there are no external resources.
|
// Dropping a glb file is simple because there are no external resources.
|
||||||
if (this.srcBlob && this.srcBlob.name.endsWith(".glb")) {
|
if (this.srcBlob && this.srcBlob.name.endsWith(".glb")) {
|
||||||
this.srcBlob.arrayBuffer().then(buffer => {
|
this.srcBlob.arrayBuffer().then(buffer => {
|
||||||
this.asset = this.loader.createAssetFromBinary(new Uint8Array(buffer));
|
this.asset = this.loader.createAsset(new Uint8Array(buffer));
|
||||||
const aabb = this.asset.getBoundingBox();
|
const aabb = this.asset.getBoundingBox();
|
||||||
this.assetRoot = this.asset.getRoot();
|
this.assetRoot = this.asset.getRoot();
|
||||||
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
||||||
this.asset.loadResources();
|
this.asset.loadResources();
|
||||||
this.animator = this.asset.getAnimator();
|
this.animator = this.asset.getInstance().getAnimator();
|
||||||
this.animationStartTime = Date.now();
|
this.animationStartTime = Date.now();
|
||||||
this._updateOverlay();
|
this._updateOverlay();
|
||||||
});
|
});
|
||||||
@@ -304,8 +304,6 @@ class FilamentViewer extends LitElement {
|
|||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
normalizeSkinningWeights: true,
|
normalizeSkinningWeights: true,
|
||||||
recomputeBoundingBoxes: false,
|
|
||||||
ignoreBindTransform: false,
|
|
||||||
asyncInterval: 30
|
asyncInterval: 30
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -320,22 +318,20 @@ class FilamentViewer extends LitElement {
|
|||||||
resourceLoader.delete();
|
resourceLoader.delete();
|
||||||
stbProvider.delete();
|
stbProvider.delete();
|
||||||
ktx2Provider.delete();
|
ktx2Provider.delete();
|
||||||
this.animator = this.asset.getAnimator();
|
this.animator = this.asset.getInstance().getAnimator();
|
||||||
this.animationStartTime = Date.now();
|
this.animationStartTime = Date.now();
|
||||||
}
|
}
|
||||||
}, config.asyncInterval);
|
}, config.asyncInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.srcBlob.arrayBuffer().then(buffer => {
|
this.srcBlob.arrayBuffer().then(buffer => {
|
||||||
this.asset = this.loader.createAssetFromJson(new Uint8Array(buffer));
|
this.asset = this.loader.createAsset(new Uint8Array(buffer));
|
||||||
const aabb = this.asset.getBoundingBox();
|
const aabb = this.asset.getBoundingBox();
|
||||||
this.assetRoot = this.asset.getRoot();
|
this.assetRoot = this.asset.getRoot();
|
||||||
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
||||||
|
|
||||||
const resourceLoader = new Filament.gltfio$ResourceLoader(this.engine,
|
const resourceLoader = new Filament.gltfio$ResourceLoader(this.engine,
|
||||||
config.normalizeSkinningWeights,
|
config.normalizeSkinningWeights);
|
||||||
config.recomputeBoundingBoxes,
|
|
||||||
config.ignoreBindTransform);
|
|
||||||
|
|
||||||
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
|
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
|
||||||
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
|
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
|
||||||
@@ -367,12 +363,7 @@ class FilamentViewer extends LitElement {
|
|||||||
return response.arrayBuffer();
|
return response.arrayBuffer();
|
||||||
}).then(arrayBuffer => {
|
}).then(arrayBuffer => {
|
||||||
const modelData = new Uint8Array(arrayBuffer);
|
const modelData = new Uint8Array(arrayBuffer);
|
||||||
if (this.src.endsWith(".glb")) {
|
this.asset = this.loader.createAsset(modelData);
|
||||||
this.asset = this.loader.createAssetFromBinary(modelData);
|
|
||||||
} else {
|
|
||||||
this.asset = this.loader.createAssetFromJson(modelData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const aabb = this.asset.getBoundingBox();
|
const aabb = this.asset.getBoundingBox();
|
||||||
this.assetRoot = this.asset.getRoot();
|
this.assetRoot = this.asset.getRoot();
|
||||||
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset);
|
||||||
@@ -380,7 +371,7 @@ class FilamentViewer extends LitElement {
|
|||||||
const basePath = '' + new URL(this.src, document.location);
|
const basePath = '' + new URL(this.src, document.location);
|
||||||
|
|
||||||
this.asset.loadResources(() => {
|
this.asset.loadResources(() => {
|
||||||
this.animator = this.asset.getAnimator();
|
this.animator = this.asset.getInstance().getAnimator();
|
||||||
this.animationStartTime = Date.now();
|
this.animationStartTime = Date.now();
|
||||||
this._applyMaterialVariant();
|
this._applyMaterialVariant();
|
||||||
}, null, basePath);
|
}, null, basePath);
|
||||||
@@ -441,14 +432,15 @@ class FilamentViewer extends LitElement {
|
|||||||
if (!this.hasAttribute("materialVariant")) {
|
if (!this.hasAttribute("materialVariant")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const names = this.asset.getMaterialVariantNames();
|
const instance = this.asset.getInstance();
|
||||||
|
const names = instance.getMaterialVariantNames();
|
||||||
const index = this.materialVariant;
|
const index = this.materialVariant;
|
||||||
if (index < 0 || index >= names.length) {
|
if (index < 0 || index >= names.length) {
|
||||||
console.error(`Material variant ${index} does not exist in this asset.`);
|
console.error(`Material variant ${index} does not exist in this asset.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.info(this.src, `Applying material variant: ${names[index]}`);
|
console.info(this.src, `Applying material variant: ${names[index]}`);
|
||||||
this.asset.applyMaterialVariant(index);
|
instance.applyMaterialVariant(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ filament-viewer::part(canvas) {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<script src="https://unpkg.com/filament@1.25.3/filament.js"></script>
|
<script src="https://unpkg.com/filament@1.44.0/filament.js"></script>
|
||||||
<script src="https://unpkg.com/gltumble"></script>
|
<script src="https://unpkg.com/gltumble"></script>
|
||||||
<script src="filament-viewer.js" type="module"></script>
|
<script src="filament-viewer.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -22,27 +22,26 @@ converting <a href="https://github.com/google/filament/blob/main/assets/models/m
|
|||||||
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
||||||
non-compressed variants for each texture, since not all platforms support the same compression
|
non-compressed variants for each texture, since not all platforms support the same compression
|
||||||
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
|
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color and two compressed variants.</span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span>
|
||||||
mipgen albedo.png albedo.ktx
|
mipgen albedo.png albedo.ktx2
|
||||||
mipgen --compression<span style="color: #666666">=</span>astc_fast_ldr_4x4 albedo.png albedo_astc.ktx
|
mipgen --compression<span style="color: #666666">=</span>uastc albedo.png albedo.ktx2
|
||||||
mipgen --compression<span style="color: #666666">=</span>s3tc_rgb_dxt1 albedo.png albedo_s3tc_srgb.ktx
|
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
||||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
|
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
|
||||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>etc_rgb8_normalxyz_40 <span style="color: #AA5D1F; font-weight: bold">\</span>
|
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>uastc_normals <span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||||
normal.png normal_etc.ktx
|
normal.png normal.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
||||||
mipgen --grayscale roughness.png roughness.ktx
|
mipgen --grayscale roughness.png roughness.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 roughness.png roughness_etc.ktx
|
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc roughness.png roughness.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
||||||
mipgen --grayscale metallic.png metallic.ktx
|
mipgen --grayscale metallic.png metallic.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 metallic.png metallic_etc.ktx
|
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc metallic.png metallic.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
||||||
mipgen --grayscale ao.png ao.ktx
|
mipgen --grayscale ao.png ao.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 ao.png ao_etc.ktx
|
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc ao.png ao.ktx2
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
||||||
@@ -207,11 +206,11 @@ when the assets have finished downloading.</p>
|
|||||||
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
||||||
was created in the app constructor.</p>
|
was created in the app constructor.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #bbbbbb"> </span>albedo_url,<span style="color: #bbbbbb"> </span>roughness_url,<span style="color: #bbbbbb"> </span>metallic_url,<span style="color: #bbbbbb"> </span>normal_url,<span style="color: #bbbbbb"> </span>ao_url],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #bbbbbb"> </span>albedo_url,<span style="color: #bbbbbb"> </span>roughness_url,<span style="color: #bbbbbb"> </span>metallic_url,<span style="color: #bbbbbb"> </span>normal_url,<span style="color: #bbbbbb"> </span>ao_url],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx1(albedo_url,<span style="color: #bbbbbb"> </span>{srgb<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #bbbbbb"> </span>{srgb<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx1(roughness_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx1(metallic_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx1(normal_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx1(ao_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);<span style="color: #bbbbbb"></span>
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sampler<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.TextureSampler(<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sampler<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.TextureSampler(<span style="color: #bbbbbb"></span>
|
||||||
<span style="color: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
|
<span style="color: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ class App {
|
|||||||
});
|
});
|
||||||
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.createTextureFromKtx1(albedo_url, {
|
const albedo = this.engine.createTextureFromKtx2(albedo_url, {
|
||||||
srgb: true
|
srgb: true
|
||||||
});
|
});
|
||||||
const roughness = this.engine.createTextureFromKtx1(roughness_url);
|
const roughness = this.engine.createTextureFromKtx2(roughness_url);
|
||||||
const metallic = this.engine.createTextureFromKtx1(metallic_url);
|
const metallic = this.engine.createTextureFromKtx2(metallic_url);
|
||||||
const normal = this.engine.createTextureFromKtx1(normal_url);
|
const normal = this.engine.createTextureFromKtx2(normal_url);
|
||||||
const ao = this.engine.createTextureFromKtx1(ao_url);
|
const ao = this.engine.createTextureFromKtx2(ao_url);
|
||||||
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||||
Filament.MagFilter.LINEAR, Filament.WrapMode.CLAMP_TO_EDGE);
|
Filament.MagFilter.LINEAR, Filament.WrapMode.CLAMP_TO_EDGE);
|
||||||
this.matinstance.setTextureParameter('albedo', albedo, sampler);
|
this.matinstance.setTextureParameter('albedo', albedo, sampler);
|
||||||
|
|||||||
+12
-5
@@ -228,8 +228,9 @@ set(MATERIAL_SRCS
|
|||||||
src/materials/dof/dofMipmap.mat
|
src/materials/dof/dofMipmap.mat
|
||||||
src/materials/dof/dofMedian.mat
|
src/materials/dof/dofMedian.mat
|
||||||
src/materials/flare/flare.mat
|
src/materials/flare/flare.mat
|
||||||
src/materials/blitLow.mat
|
|
||||||
src/materials/bloom/bloomDownsample.mat
|
src/materials/bloom/bloomDownsample.mat
|
||||||
|
src/materials/bloom/bloomDownsample2x.mat
|
||||||
|
src/materials/bloom/bloomDownsample9.mat
|
||||||
src/materials/bloom/bloomUpsample.mat
|
src/materials/bloom/bloomUpsample.mat
|
||||||
src/materials/ssao/bilateralBlur.mat
|
src/materials/ssao/bilateralBlur.mat
|
||||||
src/materials/ssao/bilateralBlurBentNormals.mat
|
src/materials/ssao/bilateralBlurBentNormals.mat
|
||||||
@@ -241,9 +242,10 @@ set(MATERIAL_SRCS
|
|||||||
src/materials/antiAliasing/fxaa.mat
|
src/materials/antiAliasing/fxaa.mat
|
||||||
src/materials/antiAliasing/taa.mat
|
src/materials/antiAliasing/taa.mat
|
||||||
src/materials/vsmMipmap.mat
|
src/materials/vsmMipmap.mat
|
||||||
|
src/materials/blitLow.mat
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MATERIAL_ES2_SRCS
|
set(MATERIAL_FL0_SRCS
|
||||||
src/materials/defaultMaterial0.mat
|
src/materials/defaultMaterial0.mat
|
||||||
src/materials/skybox0.mat
|
src/materials/skybox0.mat
|
||||||
)
|
)
|
||||||
@@ -272,6 +274,11 @@ if (NOT DFG_LUT_SIZE)
|
|||||||
endif()
|
endif()
|
||||||
message(STATUS "DFG LUT size set to ${DFG_LUT_SIZE}x${DFG_LUT_SIZE}")
|
message(STATUS "DFG LUT size set to ${DFG_LUT_SIZE}x${DFG_LUT_SIZE}")
|
||||||
|
|
||||||
|
# Whether to include FL0 materials.
|
||||||
|
if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||||
|
add_definitions(-DFILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||||
|
endif()
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Definitions
|
# Definitions
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -313,8 +320,8 @@ foreach (mat_src ${MATERIAL_SRCS})
|
|||||||
list(APPEND MATERIAL_BINS ${output_path})
|
list(APPEND MATERIAL_BINS ${output_path})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if (IS_MOBILE_TARGET AND FILAMENT_SUPPORTS_OPENGL)
|
if (FILAMENT_ENABLE_FEATURE_LEVEL_0 AND FILAMENT_SUPPORTS_OPENGL)
|
||||||
foreach (mat_src ${MATERIAL_ES2_SRCS})
|
foreach (mat_src ${MATERIAL_FL0_SRCS})
|
||||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||||
@@ -555,7 +562,7 @@ if (MSVC)
|
|||||||
set(FILAMENT_WARNINGS /W3)
|
set(FILAMENT_WARNINGS /W3)
|
||||||
else()
|
else()
|
||||||
set(FILAMENT_WARNINGS
|
set(FILAMENT_WARNINGS
|
||||||
-Wall -Wextra -Wno-unused-parameter
|
-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
|
||||||
-Wextra-semi -Wnewline-eof -Wdeprecated -Wundef
|
-Wextra-semi -Wnewline-eof -Wdeprecated -Wundef
|
||||||
-Wgnu-conditional-omitted-operand
|
-Wgnu-conditional-omitted-operand
|
||||||
-Wweak-vtables -Wnon-virtual-dtor -Wclass-varargs -Wimplicit-fallthrough
|
-Wweak-vtables -Wnon-virtual-dtor -Wclass-varargs -Wimplicit-fallthrough
|
||||||
|
|||||||
+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.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ set(SRCS
|
|||||||
src/BackendUtils.cpp
|
src/BackendUtils.cpp
|
||||||
src/BlobCacheKey.cpp
|
src/BlobCacheKey.cpp
|
||||||
src/Callable.cpp
|
src/Callable.cpp
|
||||||
|
src/CallbackManager.cpp
|
||||||
src/CircularBuffer.cpp
|
src/CircularBuffer.cpp
|
||||||
src/CommandBufferQueue.cpp
|
src/CommandBufferQueue.cpp
|
||||||
src/CommandStream.cpp
|
src/CommandStream.cpp
|
||||||
@@ -54,6 +55,7 @@ set(PRIVATE_HDRS
|
|||||||
include/private/backend/HandleAllocator.h
|
include/private/backend/HandleAllocator.h
|
||||||
include/private/backend/PlatformFactory.h
|
include/private/backend/PlatformFactory.h
|
||||||
include/private/backend/SamplerGroup.h
|
include/private/backend/SamplerGroup.h
|
||||||
|
src/CallbackManager.h
|
||||||
src/CommandStreamDispatcher.h
|
src/CommandStreamDispatcher.h
|
||||||
src/CompilerThreadPool.h
|
src/CompilerThreadPool.h
|
||||||
src/DataReshaper.h
|
src/DataReshaper.h
|
||||||
@@ -67,8 +69,6 @@ set(PRIVATE_HDRS
|
|||||||
if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMENT_USE_SWIFTSHADER)
|
if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMENT_USE_SWIFTSHADER)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
include/backend/platforms/OpenGLPlatform.h
|
include/backend/platforms/OpenGLPlatform.h
|
||||||
src/opengl/CallbackManager.h
|
|
||||||
src/opengl/CallbackManager.cpp
|
|
||||||
src/opengl/gl_headers.cpp
|
src/opengl/gl_headers.cpp
|
||||||
src/opengl/gl_headers.h
|
src/opengl/gl_headers.h
|
||||||
src/opengl/GLUtils.cpp
|
src/opengl/GLUtils.cpp
|
||||||
@@ -133,6 +133,7 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
src/metal/MetalExternalImage.mm
|
src/metal/MetalExternalImage.mm
|
||||||
src/metal/MetalHandles.mm
|
src/metal/MetalHandles.mm
|
||||||
src/metal/MetalPlatform.mm
|
src/metal/MetalPlatform.mm
|
||||||
|
src/metal/MetalShaderCompiler.mm
|
||||||
src/metal/MetalState.mm
|
src/metal/MetalState.mm
|
||||||
src/metal/MetalTimerQuery.mm
|
src/metal/MetalTimerQuery.mm
|
||||||
src/metal/MetalUtils.mm
|
src/metal/MetalUtils.mm
|
||||||
@@ -355,7 +356,7 @@ if (MSVC)
|
|||||||
set(FILAMENT_WARNINGS /W3)
|
set(FILAMENT_WARNINGS /W3)
|
||||||
else()
|
else()
|
||||||
set(FILAMENT_WARNINGS
|
set(FILAMENT_WARNINGS
|
||||||
-Wall -Wextra -Wno-unused-parameter
|
-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
|
||||||
-Wextra-semi -Wnewline-eof -Wdeprecated -Wundef
|
-Wextra-semi -Wnewline-eof -Wdeprecated -Wundef
|
||||||
-Wgnu-conditional-omitted-operand
|
-Wgnu-conditional-omitted-operand
|
||||||
-Wweak-vtables -Wnon-virtual-dtor -Wclass-varargs -Wimplicit-fallthrough
|
-Wweak-vtables -Wnon-virtual-dtor -Wclass-varargs -Wimplicit-fallthrough
|
||||||
@@ -396,8 +397,8 @@ install(DIRECTORY ${PUBLIC_HDR_DIR}/backend DESTINATION include)
|
|||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
option(INSTALL_BACKEND_TEST "Install the backend test library so it can be consumed on iOS" OFF)
|
option(INSTALL_BACKEND_TEST "Install the backend test library so it can be consumed on iOS" OFF)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE OR LINUX)
|
||||||
add_library(backend_test STATIC
|
set(BACKEND_TEST_SRC
|
||||||
test/BackendTest.cpp
|
test/BackendTest.cpp
|
||||||
test/ShaderGenerator.cpp
|
test/ShaderGenerator.cpp
|
||||||
test/TrianglePrimitive.cpp
|
test/TrianglePrimitive.cpp
|
||||||
@@ -409,18 +410,26 @@ if (APPLE)
|
|||||||
test/test_BufferUpdates.cpp
|
test/test_BufferUpdates.cpp
|
||||||
test/test_MRT.cpp
|
test/test_MRT.cpp
|
||||||
test/test_LoadImage.cpp
|
test/test_LoadImage.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
|
||||||
)
|
)
|
||||||
|
set(BACKEND_TEST_LIBS
|
||||||
target_link_libraries(backend_test PRIVATE
|
|
||||||
backend
|
backend
|
||||||
getopt
|
getopt
|
||||||
gtest
|
gtest
|
||||||
|
imageio
|
||||||
filamat
|
filamat
|
||||||
SPIRV
|
SPIRV
|
||||||
spirv-cross-glsl)
|
spirv-cross-glsl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
# TODO: we should expand this test to Linux and other platforms.
|
||||||
|
list(APPEND BACKEND_TEST_SRC
|
||||||
|
test/test_RenderExternalImage.cpp)
|
||||||
|
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||||
|
target_link_libraries(backend_test PRIVATE ${BACKEND_TEST_LIBS})
|
||||||
|
|
||||||
set(BACKEND_TEST_DEPS
|
set(BACKEND_TEST_DEPS
|
||||||
OGLCompiler
|
OGLCompiler
|
||||||
@@ -434,12 +443,11 @@ if (APPLE)
|
|||||||
glslang
|
glslang
|
||||||
spirv-cross-core
|
spirv-cross-core
|
||||||
spirv-cross-glsl
|
spirv-cross-glsl
|
||||||
spirv-cross-msl
|
spirv-cross-msl)
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT IOS)
|
if (NOT IOS)
|
||||||
target_link_libraries(backend_test PRIVATE image imageio)
|
target_link_libraries(backend_test PRIVATE image imageio)
|
||||||
list(APPEND BACKEND_TEST_DEPS image imageio)
|
list(APPEND BACKEND_TEST_DEPS image)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(BACKEND_TEST_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libbackendtest_combined.a")
|
set(BACKEND_TEST_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libbackendtest_combined.a")
|
||||||
@@ -453,15 +461,21 @@ if (APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties(backend_test PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test PROPERTIES FOLDER Tests)
|
||||||
endif()
|
|
||||||
|
|
||||||
if (APPLE AND NOT IOS)
|
if (APPLE AND NOT IOS)
|
||||||
add_executable(backend_test_mac test/mac_runner.mm)
|
add_executable(backend_test_mac test/mac_runner.mm)
|
||||||
target_link_libraries(backend_test_mac PRIVATE "-framework Metal -framework AppKit -framework QuartzCore")
|
target_link_libraries(backend_test_mac PRIVATE "-framework Metal -framework AppKit -framework QuartzCore")
|
||||||
# Because each test case is a separate file, the -force_load flag is necessary to prevent the
|
# Because each test case is a separate file, the -force_load flag is necessary to prevent the
|
||||||
# linker from removing "unused" symbols.
|
# linker from removing "unused" symbols.
|
||||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LINUX)
|
||||||
|
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
||||||
|
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
||||||
|
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed
|
* Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed
|
||||||
* by pointer as the callback. e.g.:
|
* by pointer as the callback. e.g.:
|
||||||
* auto bd = BufferDescriptor::make(buffer, size, &Foo::method, foo);
|
* auto bd = BufferDescriptor::make<Foo, &Foo::method>(buffer, size, foo);
|
||||||
*
|
*
|
||||||
* @param buffer Memory address of the CPU buffer to reference
|
* @param buffer Memory address of the CPU buffer to reference
|
||||||
* @param size Size of the CPU buffer in bytes
|
* @param size Size of the CPU buffer in bytes
|
||||||
@@ -121,12 +121,12 @@ public:
|
|||||||
* @return a new BufferDescriptor
|
* @return a new BufferDescriptor
|
||||||
*/
|
*/
|
||||||
template<typename T, void(T::*method)(void const*, size_t)>
|
template<typename T, void(T::*method)(void const*, size_t)>
|
||||||
static BufferDescriptor make(
|
static BufferDescriptor make(void const* buffer, size_t size, T* data,
|
||||||
void const* buffer, size_t size, T* data, CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return {
|
return {
|
||||||
buffer, size,
|
buffer, size,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
(*static_cast<T**>(u)->*method)(b, s);
|
(static_cast<T*>(u)->*method)(b, s);
|
||||||
}, data
|
}, data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -145,14 +145,14 @@ public:
|
|||||||
* @return a new BufferDescriptor
|
* @return a new BufferDescriptor
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static BufferDescriptor make(
|
static BufferDescriptor make(void const* buffer, size_t size, T&& functor,
|
||||||
void const* buffer, size_t size, T&& functor, CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return {
|
return {
|
||||||
buffer, size,
|
buffer, size,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
T& that = *static_cast<T*>(u);
|
T* const that = static_cast<T*>(u);
|
||||||
that(b, s);
|
that->operator()(b, s);
|
||||||
delete &that;
|
delete that;
|
||||||
},
|
},
|
||||||
new T(std::forward<T>(functor))
|
new T(std::forward<T>(functor))
|
||||||
};
|
};
|
||||||
@@ -201,7 +201,7 @@ public:
|
|||||||
return mUser;
|
return mUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! CPU mempry-buffer virtual address
|
//! CPU memory-buffer virtual address
|
||||||
void* buffer = nullptr;
|
void* buffer = nullptr;
|
||||||
|
|
||||||
//! CPU memory-buffer size in bytes
|
//! CPU memory-buffer size in bytes
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
|
|||||||
*/
|
*/
|
||||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10;
|
static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the SwapChain should also contain a stencil component.
|
||||||
|
*/
|
||||||
|
static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = 0x20;
|
||||||
|
|
||||||
|
|
||||||
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
|
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
|
||||||
@@ -138,6 +143,30 @@ static constexpr const char* backendToString(Backend backend) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the shader language. Similar to the above backend enum, but the OpenGL backend can select
|
||||||
|
* between two shader languages: ESSL 1.0 and ESSL 3.0.
|
||||||
|
*/
|
||||||
|
enum class ShaderLanguage {
|
||||||
|
ESSL1 = 0,
|
||||||
|
ESSL3 = 1,
|
||||||
|
SPIRV = 2,
|
||||||
|
MSL = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||||
|
switch (shaderLanguage) {
|
||||||
|
case ShaderLanguage::ESSL1:
|
||||||
|
return "ESSL 1.0";
|
||||||
|
case ShaderLanguage::ESSL3:
|
||||||
|
return "ESSL 3.0";
|
||||||
|
case ShaderLanguage::SPIRV:
|
||||||
|
return "SPIR-V";
|
||||||
|
case ShaderLanguage::MSL:
|
||||||
|
return "MSL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitmask for selecting render buffers
|
* Bitmask for selecting render buffers
|
||||||
*/
|
*/
|
||||||
@@ -813,22 +842,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<uint64_t const*>(reinterpret_cast<char const*>(&p));
|
return *reinterpret_cast<uint32_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<uint64_t const*>(reinterpret_cast<char const*>(&lhs));
|
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||||
auto* pRhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&rhs));
|
auto* pRhs = reinterpret_cast<uint32_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<uint64_t const*>(reinterpret_cast<char const*>(&lhs));
|
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||||
auto* pRhs = reinterpret_cast<uint64_t const*>(reinterpret_cast<char const*>(&rhs));
|
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||||
return *pLhs == *pRhs;
|
return *pLhs == *pRhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -838,6 +867,7 @@ 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
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public:
|
|||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, type, alignment, left, top, stride,
|
return { buffer, size, format, type, alignment, left, top, stride,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
(*static_cast<T**>(u)->*method)(b, s); }, data };
|
(static_cast<T*>(u)->*method)(b, s); }, data };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, void(T::*method)(void const*, size_t)>
|
template<typename T, void(T::*method)(void const*, size_t)>
|
||||||
@@ -149,7 +149,7 @@ public:
|
|||||||
PixelDataFormat format, PixelDataType type, T* data,
|
PixelDataFormat format, PixelDataType type, T* data,
|
||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, type, handler, [](void* b, size_t s, void* u) {
|
return { buffer, size, format, type, handler, [](void* b, size_t s, void* u) {
|
||||||
(*static_cast<T**>(u)->*method)(b, s); }, data };
|
(static_cast<T*>(u)->*method)(b, s); }, data };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, void(T::*method)(void const*, size_t)>
|
template<typename T, void(T::*method)(void const*, size_t)>
|
||||||
@@ -157,7 +157,7 @@ public:
|
|||||||
backend::CompressedPixelDataType format, uint32_t imageSize, T* data,
|
backend::CompressedPixelDataType format, uint32_t imageSize, T* data,
|
||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, imageSize, handler, [](void* b, size_t s, void* u) {
|
return { buffer, size, format, imageSize, handler, [](void* b, size_t s, void* u) {
|
||||||
(*static_cast<T**>(u)->*method)(b, s); }, data
|
(static_cast<T*>(u)->*method)(b, s); }, data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,9 +168,9 @@ public:
|
|||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, type, alignment, left, top, stride,
|
return { buffer, size, format, type, alignment, left, top, stride,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
T& that = *static_cast<T*>(u);
|
T* const that = static_cast<T*>(u);
|
||||||
that(b, s);
|
that->operator()(b, s);
|
||||||
delete &that;
|
delete that;
|
||||||
}, new T(std::forward<T>(functor))
|
}, new T(std::forward<T>(functor))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -181,9 +181,9 @@ public:
|
|||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, type,
|
return { buffer, size, format, type,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
T& that = *static_cast<T*>(u);
|
T* const that = static_cast<T*>(u);
|
||||||
that(b, s);
|
that->operator()(b, s);
|
||||||
delete &that;
|
delete that;
|
||||||
}, new T(std::forward<T>(functor))
|
}, new T(std::forward<T>(functor))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -194,9 +194,9 @@ public:
|
|||||||
CallbackHandler* handler = nullptr) noexcept {
|
CallbackHandler* handler = nullptr) noexcept {
|
||||||
return { buffer, size, format, imageSize,
|
return { buffer, size, format, imageSize,
|
||||||
handler, [](void* b, size_t s, void* u) {
|
handler, [](void* b, size_t s, void* u) {
|
||||||
T& that = *static_cast<T*>(u);
|
T* const that = static_cast<T*>(u);
|
||||||
that(b, s);
|
that->operator()(b, s);
|
||||||
delete &that;
|
delete that;
|
||||||
}, new T(std::forward<T>(functor))
|
}, new T(std::forward<T>(functor))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ public:
|
|||||||
* Driver clamps to valid values.
|
* Driver clamps to valid values.
|
||||||
*/
|
*/
|
||||||
size_t handleArenaSize = 0;
|
size_t handleArenaSize = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this number of most-recently destroyed textures will be tracked for use-after-free.
|
||||||
|
* Throws an exception when a texture is freed but still bound to a SamplerGroup and used in
|
||||||
|
* a draw call. 0 disables completely. Currently only respected by the Metal backend.
|
||||||
|
*/
|
||||||
|
size_t textureUseAfterFreePoolSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Platform() noexcept;
|
Platform() noexcept;
|
||||||
@@ -107,6 +114,7 @@ public:
|
|||||||
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
|
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
|
||||||
* from any thread from the time at which setBlobFunc is called until the time that Platform
|
* from any thread from the time at which setBlobFunc is called until the time that Platform
|
||||||
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
|
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
|
||||||
|
* Either function can be null.
|
||||||
*
|
*
|
||||||
* @param insertBlob an Invocable that inserts a new value into the cache and associates
|
* @param insertBlob an Invocable that inserts a new value into the cache and associates
|
||||||
* it with the given key
|
* it with the given key
|
||||||
@@ -116,9 +124,21 @@ public:
|
|||||||
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
|
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if setBlobFunc was called.
|
* @return true if insertBlob is valid.
|
||||||
*/
|
*/
|
||||||
bool hasBlobFunc() const noexcept;
|
bool hasInsertBlobFunc() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if retrieveBlob is valid.
|
||||||
|
*/
|
||||||
|
bool hasRetrieveBlobFunc() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if either of insertBlob or retrieveBlob are valid.
|
||||||
|
*/
|
||||||
|
bool hasBlobFunc() const noexcept {
|
||||||
|
return hasInsertBlobFunc() || hasRetrieveBlobFunc();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To insert a new binary value into the cache and associate it with a given
|
* To insert a new binary value into the cache and associate it with a given
|
||||||
|
|||||||
@@ -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;
|
Program& operator=(Program&& rhs) noexcept = delete;
|
||||||
|
|
||||||
~Program() noexcept;
|
~Program() noexcept;
|
||||||
|
|
||||||
@@ -104,8 +104,9 @@ 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
|
||||||
std::variant<int32_t, float, bool> value; // value and type
|
Type value; // value and type
|
||||||
};
|
};
|
||||||
|
|
||||||
Program& specializationConstants(
|
Program& specializationConstants(
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ public:
|
|||||||
void createContext(bool shared) override;
|
void createContext(bool shared) override;
|
||||||
void releaseContext() noexcept override;
|
void releaseContext() noexcept override;
|
||||||
|
|
||||||
|
// Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default.
|
||||||
|
virtual bool isOpenGL() const noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
@@ -126,6 +129,7 @@ protected:
|
|||||||
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
|
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
|
||||||
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
|
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
|
||||||
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
|
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
|
||||||
|
// mEGLConfig is valid only if ext.egl.KHR_no_config_context is false
|
||||||
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
|
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
|
||||||
Config mContextAttribs;
|
Config mContextAttribs;
|
||||||
std::vector<EGLContext> mAdditionalContexts;
|
std::vector<EGLContext> mAdditionalContexts;
|
||||||
@@ -146,8 +150,8 @@ protected:
|
|||||||
|
|
||||||
void initializeGlExtensions() noexcept;
|
void initializeGlExtensions() noexcept;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
EGLConfig findSwapChainConfig(uint64_t flags) const;
|
EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ public:
|
|||||||
|
|
||||||
Driver* createDriver(void* sharedContext,
|
Driver* createDriver(void* sharedContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool isOpenGL() const noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/PrivateImplementation.h>
|
#include <utils/PrivateImplementation.h>
|
||||||
|
|
||||||
@@ -89,36 +90,44 @@ public:
|
|||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// ---------- Platform Customization options ----------
|
// ---------- Platform Customization options ----------
|
||||||
|
struct Customization {
|
||||||
/**
|
/**
|
||||||
* The client preference can be stored within the struct. We allow for two specification of
|
* The client can specify the GPU (i.e. VkDevice) for the platform. We allow the
|
||||||
* preference:
|
* following preferences:
|
||||||
* 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`.
|
* 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`. Empty string
|
||||||
* 2) Index of the device in the list as returned by vkEnumeratePhysicalDevices.
|
* by default.
|
||||||
|
* 2) Index of the device in the list as returned by
|
||||||
|
* `vkEnumeratePhysicalDevices`. -1 by default to indicate no preference.
|
||||||
*/
|
*/
|
||||||
struct GPUPreference {
|
struct GPUPreference {
|
||||||
std::string deviceName;
|
utils::CString deviceName;
|
||||||
int8_t index = -1;
|
int8_t index = -1;
|
||||||
|
} gpu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the platform supports sRGB swapchain. Default is true.
|
||||||
|
*/
|
||||||
|
bool isSRGBSwapChainSupported = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the platform window is resized, we will flush and wait on the command queues
|
||||||
|
* before recreating the swapchain. Default is true.
|
||||||
|
*/
|
||||||
|
bool flushAndWaitOnWindowResize = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client can provide a preference over the GPU to use in the vulkan instance
|
* Client can override to indicate customized behavior or parameter for their platform.
|
||||||
* @return `GPUPreference` struct that indicates the client's preference
|
* @return `Customization` struct that indicates the client's platform
|
||||||
|
* customizations.
|
||||||
*/
|
*/
|
||||||
virtual GPUPreference getPreferredGPU() noexcept {
|
virtual Customization getCustomization() const noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- End platform customization options --------
|
// -------- End platform customization options --------
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the platform supports sRGB swapchain. This is true by default, and the client
|
|
||||||
* needs to override this method to specify otherwise.
|
|
||||||
* @return Whether the platform supports sRGB swapchain.
|
|
||||||
*/
|
|
||||||
virtual bool isSRGBSwapChainSupported() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the images handles and format of the memory backing the swapchain. This should be called
|
* Get the images handles and format of the memory backing the swapchain. This should be called
|
||||||
* after createSwapChain() or after recreateIfResized().
|
* after createSwapChain() or after recreateIfResized().
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <backend/PipelineState.h>
|
#include <backend/PipelineState.h>
|
||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, importTexture,
|
|||||||
backend::TextureUsage, usage)
|
backend::TextureUsage, usage)
|
||||||
|
|
||||||
DECL_DRIVER_API_R_N(backend::SamplerGroupHandle, createSamplerGroup,
|
DECL_DRIVER_API_R_N(backend::SamplerGroupHandle, createSamplerGroup,
|
||||||
uint32_t, size)
|
uint32_t, size, utils::FixedSizeString<32>, debugName)
|
||||||
|
|
||||||
DECL_DRIVER_API_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
|
DECL_DRIVER_API_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
|
||||||
backend::VertexBufferHandle, vbh,
|
backend::VertexBufferHandle, vbh,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#define HandleAllocatorGL HandleAllocator<16, 64, 208>
|
#define HandleAllocatorGL HandleAllocator<16, 64, 208>
|
||||||
#define HandleAllocatorVK HandleAllocator<16, 64, 880>
|
#define HandleAllocatorVK HandleAllocator<16, 64, 880>
|
||||||
#define HandleAllocatorMTL HandleAllocator<16, 64, 576>
|
#define HandleAllocatorMTL HandleAllocator<16, 64, 584>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -239,14 +239,16 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: We should be using a Spinlock here, at least on platforms where mutexes are not
|
||||||
|
// efficient (i.e. non-Linux). However, we've seen some hangs on that spinlock, which
|
||||||
|
// we don't understand well (b/308029108).
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
using HandleArena = utils::Arena<Allocator,
|
using HandleArena = utils::Arena<Allocator,
|
||||||
utils::LockingPolicy::SpinLock,
|
utils::LockingPolicy::Mutex,
|
||||||
utils::TrackingPolicy::DebugAndHighWatermark>;
|
utils::TrackingPolicy::DebugAndHighWatermark>;
|
||||||
#else
|
#else
|
||||||
using HandleArena = utils::Arena<Allocator,
|
using HandleArena = utils::Arena<Allocator,
|
||||||
utils::LockingPolicy::SpinLock>;
|
utils::LockingPolicy::Mutex>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// allocateHandle()/deallocateHandle() selects the pool to use at compile-time based on the
|
// allocateHandle()/deallocateHandle() selects the pool to use at compile-time based on the
|
||||||
@@ -256,6 +258,7 @@ private:
|
|||||||
HandleBase::HandleId allocateHandle() noexcept {
|
HandleBase::HandleId allocateHandle() noexcept {
|
||||||
if constexpr (SIZE <= P0) { return allocateHandleInPool<P0>(); }
|
if constexpr (SIZE <= P0) { return allocateHandleInPool<P0>(); }
|
||||||
if constexpr (SIZE <= P1) { return allocateHandleInPool<P1>(); }
|
if constexpr (SIZE <= P1) { return allocateHandleInPool<P1>(); }
|
||||||
|
static_assert(SIZE <= P2);
|
||||||
return allocateHandleInPool<P2>();
|
return allocateHandleInPool<P2>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,6 +269,7 @@ private:
|
|||||||
} else if constexpr (SIZE <= P1) {
|
} else if constexpr (SIZE <= P1) {
|
||||||
deallocateHandleFromPool<P1>(id);
|
deallocateHandleFromPool<P1>(id);
|
||||||
} else {
|
} else {
|
||||||
|
static_assert(SIZE <= P2);
|
||||||
deallocateHandleFromPool<P2>(id);
|
deallocateHandleFromPool<P2>(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -12,10 +12,11 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* 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.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_OPENGL_CALLBACKMANAGER_H
|
#ifndef TNT_FILAMENT_BACKEND_CALLBACKMANAGER_H
|
||||||
#define TNT_FILAMENT_BACKEND_OPENGL_CALLBACKMANAGER_H
|
#define TNT_FILAMENT_BACKEND_CALLBACKMANAGER_H
|
||||||
|
|
||||||
#include <backend/CallbackHandler.h>
|
#include <backend/CallbackHandler.h>
|
||||||
|
|
||||||
@@ -95,4 +96,4 @@ private:
|
|||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|
||||||
#endif // TNT_FILAMENT_BACKEND_OPENGL_CALLBACKMANAGER_H
|
#endif // TNT_FILAMENT_BACKEND_CALLBACKMANAGER_H
|
||||||
@@ -28,14 +28,16 @@ bool Platform::pumpEvents() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Platform::setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept {
|
void Platform::setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept {
|
||||||
if (!mInsertBlob && !mRetrieveBlob) {
|
|
||||||
mInsertBlob = std::move(insertBlob);
|
mInsertBlob = std::move(insertBlob);
|
||||||
mRetrieveBlob = std::move(retrieveBlob);
|
mRetrieveBlob = std::move(retrieveBlob);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Platform::hasBlobFunc() const noexcept {
|
bool Platform::hasInsertBlobFunc() const noexcept {
|
||||||
return mInsertBlob && mRetrieveBlob;
|
return bool(mInsertBlob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Platform::hasRetrieveBlobFunc() const noexcept {
|
||||||
|
return bool(mRetrieveBlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {
|
void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {
|
||||||
|
|||||||
@@ -26,17 +26,6 @@ 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 {
|
||||||
|
|||||||
@@ -18,12 +18,15 @@
|
|||||||
#define TNT_METALCONTEXT_H
|
#define TNT_METALCONTEXT_H
|
||||||
|
|
||||||
#include "MetalResourceTracker.h"
|
#include "MetalResourceTracker.h"
|
||||||
|
#include "MetalShaderCompiler.h"
|
||||||
#include "MetalState.h"
|
#include "MetalState.h"
|
||||||
|
|
||||||
#include <CoreVideo/CVMetalTextureCache.h>
|
#include <CoreVideo/CVMetalTextureCache.h>
|
||||||
#include <Metal/Metal.h>
|
#include <Metal/Metal.h>
|
||||||
#include <QuartzCore/QuartzCore.h>
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
#include <utils/FixedCircularBuffer.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@@ -53,6 +56,9 @@ struct MetalVertexBuffer;
|
|||||||
constexpr static uint8_t MAX_SAMPLE_COUNT = 8; // Metal devices support at most 8 MSAA samples
|
constexpr static uint8_t MAX_SAMPLE_COUNT = 8; // Metal devices support at most 8 MSAA samples
|
||||||
|
|
||||||
struct MetalContext {
|
struct MetalContext {
|
||||||
|
explicit MetalContext(size_t metalFreedTextureListSize)
|
||||||
|
: texturesToDestroy(metalFreedTextureListSize) {}
|
||||||
|
|
||||||
MetalDriver* driver;
|
MetalDriver* driver;
|
||||||
id<MTLDevice> device = nullptr;
|
id<MTLDevice> device = nullptr;
|
||||||
id<MTLCommandQueue> commandQueue = nullptr;
|
id<MTLCommandQueue> commandQueue = nullptr;
|
||||||
@@ -111,6 +117,14 @@ struct MetalContext {
|
|||||||
tsl::robin_set<MetalSamplerGroup*> samplerGroups;
|
tsl::robin_set<MetalSamplerGroup*> samplerGroups;
|
||||||
tsl::robin_set<MetalTexture*> textures;
|
tsl::robin_set<MetalTexture*> textures;
|
||||||
|
|
||||||
|
// This circular buffer implements delayed destruction for Metal texture handles. It keeps a
|
||||||
|
// handle to a fixed number of the most recently destroyed texture handles. When we're asked to
|
||||||
|
// destroy a texture handle, we free its texture memory, but keep the MetalTexture object alive,
|
||||||
|
// marking it as "terminated". If we later are asked to use that texture, we can check its
|
||||||
|
// terminated status and throw an Objective-C error instead of crashing, which is helpful for
|
||||||
|
// debugging use-after-free issues in release builds.
|
||||||
|
utils::FixedCircularBuffer<Handle<HwTexture>> texturesToDestroy;
|
||||||
|
|
||||||
MetalBufferPool* bufferPool;
|
MetalBufferPool* bufferPool;
|
||||||
|
|
||||||
MetalSwapChain* currentDrawSwapChain = nil;
|
MetalSwapChain* currentDrawSwapChain = nil;
|
||||||
@@ -136,6 +150,8 @@ struct MetalContext {
|
|||||||
|
|
||||||
MTLViewport currentViewport;
|
MTLViewport currentViewport;
|
||||||
|
|
||||||
|
MetalShaderCompiler* shaderCompiler = nullptr;
|
||||||
|
|
||||||
#if defined(FILAMENT_METAL_PROFILING)
|
#if defined(FILAMENT_METAL_PROFILING)
|
||||||
// Logging and profiling.
|
// Logging and profiling.
|
||||||
os_log_t log;
|
os_log_t log;
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ namespace backend {
|
|||||||
class MetalPlatform;
|
class MetalPlatform;
|
||||||
|
|
||||||
class MetalBuffer;
|
class MetalBuffer;
|
||||||
|
class MetalProgram;
|
||||||
class MetalSamplerGroup;
|
class MetalSamplerGroup;
|
||||||
class MetalTexture;
|
class MetalTexture;
|
||||||
struct MetalUniformBuffer;
|
struct MetalUniformBuffer;
|
||||||
struct MetalContext;
|
struct MetalContext;
|
||||||
struct MetalProgram;
|
|
||||||
struct BufferState;
|
struct BufferState;
|
||||||
|
|
||||||
#ifndef FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB
|
#ifndef FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ UTILS_NOINLINE
|
|||||||
Driver* MetalDriver::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) {
|
Driver* MetalDriver::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) {
|
||||||
assert_invariant(platform);
|
assert_invariant(platform);
|
||||||
size_t defaultSize = FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
size_t defaultSize = FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||||
Platform::DriverConfig validConfig { .handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize) };
|
Platform::DriverConfig validConfig {driverConfig};
|
||||||
|
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
||||||
return new MetalDriver(platform, validConfig);
|
return new MetalDriver(platform, validConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
|
|||||||
|
|
||||||
MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
|
MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||||
: mPlatform(*platform),
|
: mPlatform(*platform),
|
||||||
mContext(new MetalContext),
|
mContext(new MetalContext(driverConfig.textureUseAfterFreePoolSize)),
|
||||||
mHandleAllocator("Handles", driverConfig.handleArenaSize) {
|
mHandleAllocator("Handles", driverConfig.handleArenaSize) {
|
||||||
mContext->driver = this;
|
mContext->driver = this;
|
||||||
|
|
||||||
@@ -143,6 +144,9 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
|||||||
mContext->eventListener = [[MTLSharedEventListener alloc] initWithDispatchQueue:queue];
|
mContext->eventListener = [[MTLSharedEventListener alloc] initWithDispatchQueue:queue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mContext->shaderCompiler = new MetalShaderCompiler(mContext->device, *this);
|
||||||
|
mContext->shaderCompiler->init();
|
||||||
|
|
||||||
#if defined(FILAMENT_METAL_PROFILING)
|
#if defined(FILAMENT_METAL_PROFILING)
|
||||||
mContext->log = os_log_create("com.google.filament", "Metal");
|
mContext->log = os_log_create("com.google.filament", "Metal");
|
||||||
mContext->signpostId = os_signpost_id_generate(mContext->log);
|
mContext->signpostId = os_signpost_id_generate(mContext->log);
|
||||||
@@ -157,6 +161,7 @@ MetalDriver::~MetalDriver() noexcept {
|
|||||||
delete mContext->bufferPool;
|
delete mContext->bufferPool;
|
||||||
delete mContext->blitter;
|
delete mContext->blitter;
|
||||||
delete mContext->timerQueryImpl;
|
delete mContext->timerQueryImpl;
|
||||||
|
delete mContext->shaderCompiler;
|
||||||
delete mContext;
|
delete mContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,8 +308,9 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
|||||||
target, levels, format, samples, width, height, depth, usage, metalTexture));
|
target, levels, format, samples, width, height, depth, usage, metalTexture));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t size) {
|
void MetalDriver::createSamplerGroupR(
|
||||||
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(sbh, size));
|
Handle<HwSamplerGroup> sbh, uint32_t size, utils::FixedSizeString<32> debugName) {
|
||||||
|
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(sbh, size, debugName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||||
@@ -317,7 +323,7 @@ void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
|
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
|
||||||
construct_handle<MetalProgram>(rph, mContext->device, program);
|
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
|
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
|
||||||
@@ -345,7 +351,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->updateLodRange(buffer.level);
|
colorTexture->extendLodRangeTo(buffer.level);
|
||||||
colorAttachments[i] = { colorTexture, color[i].level, color[i].layer };
|
colorAttachments[i] = { colorTexture, color[i].level, color[i].layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +362,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->updateLodRange(depth.level);
|
depthTexture->extendLodRangeTo(depth.level);
|
||||||
depthAttachment = { depthTexture, depth.level, depth.layer };
|
depthAttachment = { depthTexture, depth.level, depth.layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +373,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->updateLodRange(stencil.level);
|
stencilTexture->extendLodRangeTo(stencil.level);
|
||||||
stencilAttachment = { stencilTexture, stencil.level, stencil.layer };
|
stencilAttachment = { stencilTexture, stencil.level, stencil.layer };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,8 +536,18 @@ void MetalDriver::destroyTexture(Handle<HwTexture> th) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mContext->textures.erase(handle_cast<MetalTexture>(th));
|
auto* metalTexture = handle_cast<MetalTexture>(th);
|
||||||
destruct_handle<MetalTexture>(th);
|
mContext->textures.erase(metalTexture);
|
||||||
|
|
||||||
|
// Free memory from the texture and mark it as freed.
|
||||||
|
metalTexture->terminate();
|
||||||
|
|
||||||
|
// Add this texture handle to our texturesToDestroy queue to be destroyed later.
|
||||||
|
if (auto handleToFree = mContext->texturesToDestroy.push(th)) {
|
||||||
|
// If texturesToDestroy is full, then .push evicts the oldest texture handle in the
|
||||||
|
// queue (or simply th, if use-after-free detection is disabled).
|
||||||
|
destruct_handle<MetalTexture>(handleToFree.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
void MetalDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||||
@@ -557,6 +573,12 @@ void MetalDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::terminate() {
|
void MetalDriver::terminate() {
|
||||||
|
// Terminate any outstanding MetalTextures.
|
||||||
|
while (!mContext->texturesToDestroy.empty()) {
|
||||||
|
Handle<HwTexture> toDestroy = mContext->texturesToDestroy.pop();
|
||||||
|
destruct_handle<MetalTexture>(toDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
// finish() will flush the pending command buffer and will ensure all GPU work has finished.
|
// finish() will flush the pending command buffer and will ensure all GPU work has finished.
|
||||||
// This must be done before calling bufferPool->reset() to ensure no buffers are in flight.
|
// This must be done before calling bufferPool->reset() to ensure no buffers are in flight.
|
||||||
finish();
|
finish();
|
||||||
@@ -566,6 +588,7 @@ void MetalDriver::terminate() {
|
|||||||
|
|
||||||
MetalExternalImage::shutdown(*mContext);
|
MetalExternalImage::shutdown(*mContext);
|
||||||
mContext->blitter->shutdown();
|
mContext->blitter->shutdown();
|
||||||
|
mContext->shaderCompiler->terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderModel MetalDriver::getShaderModel() const noexcept {
|
ShaderModel MetalDriver::getShaderModel() const noexcept {
|
||||||
@@ -701,7 +724,7 @@ bool MetalDriver::isStereoSupported() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetalDriver::isParallelShaderCompileSupported() {
|
bool MetalDriver::isParallelShaderCompileSupported() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||||
@@ -789,6 +812,8 @@ 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,
|
||||||
@@ -852,13 +877,17 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
|
|||||||
assert_invariant(sb->size == data.size / sizeof(SamplerDescriptor));
|
assert_invariant(sb->size == data.size / sizeof(SamplerDescriptor));
|
||||||
auto const* const samplers = (SamplerDescriptor const*) data.buffer;
|
auto const* const samplers = (SamplerDescriptor const*) data.buffer;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
// Verify that all the textures in the sampler group are still alive.
|
||||||
// In debug builds, verify that all the textures in the sampler group are still alive.
|
|
||||||
// These bugs lead to memory corruption and can be difficult to track down.
|
// These bugs lead to memory corruption and can be difficult to track down.
|
||||||
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) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// The difference between this check and the one below is that in release, we do this for
|
||||||
|
// only a set number of recently freed textures, while the debug check is exhaustive.
|
||||||
|
auto* metalTexture = handle_cast<MetalTexture>(samplers[s].t);
|
||||||
|
metalTexture->checkUseAfterFree(sb->debugName.c_str(), s);
|
||||||
|
#ifndef NDEBUG
|
||||||
auto iter = mContext->textures.find(handle_cast<MetalTexture>(samplers[s].t));
|
auto iter = mContext->textures.find(handle_cast<MetalTexture>(samplers[s].t));
|
||||||
if (iter == mContext->textures.end()) {
|
if (iter == mContext->textures.end()) {
|
||||||
utils::slog.e << "updateSamplerGroup: texture #"
|
utils::slog.e << "updateSamplerGroup: texture #"
|
||||||
@@ -866,8 +895,8 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
|
|||||||
<< samplers[s].t << utils::io::endl;
|
<< samplers[s].t << utils::io::endl;
|
||||||
}
|
}
|
||||||
assert_invariant(iter != mContext->textures.end());
|
assert_invariant(iter != mContext->textures.end());
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Create a MTLArgumentEncoder for these textures.
|
// Create a MTLArgumentEncoder for these textures.
|
||||||
// Ideally, we would create this encoder at createSamplerGroup time, but we need to know the
|
// Ideally, we would create this encoder at createSamplerGroup time, but we need to know the
|
||||||
@@ -900,29 +929,24 @@ 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 bind what we can now and wait
|
// the argument buffer representing the sampler group. So, we wait until draw call time to bind
|
||||||
// until draw call time to bind any special cases (done in finalizeSamplerGroup).
|
// textures (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.
|
||||||
// Even if we do know all the final textures at this point, we still wait until draw call time
|
// finalizeSamplerGroup has one additional responsibility: to call useResources for all the
|
||||||
// to call finalizeSamplerGroup, which has one additional responsibility: to call useResources
|
// textures, which is required by Metal.
|
||||||
// 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 sampler to empty slots.
|
||||||
// Metal requires all samplers referenced in shaders to be bound.
|
// Metal requires all samplers referenced in shaders to be bound.
|
||||||
id<MTLTexture> empty = getOrCreateEmptyTexture(mContext);
|
// An empty texture will be assigned inside finalizeSamplerGroup.
|
||||||
sb->setFinalizedTexture(s, empty);
|
|
||||||
|
|
||||||
id<MTLSamplerState> sampler = mContext->samplerStateCache.getOrCreateState({});
|
id<MTLSamplerState> sampler = mContext->samplerStateCache.getOrCreateState({});
|
||||||
sb->setFinalizedSampler(s, sampler);
|
sb->setFinalizedSampler(s, sampler);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, bind the sampler state. We always know the full sampler state at
|
// Bind the sampler state. We always know the full sampler state at updateSamplerGroup time.
|
||||||
// updateSamplerGroup time.
|
|
||||||
SamplerState samplerState {
|
SamplerState samplerState {
|
||||||
.samplerParams = samplers[s].s,
|
.samplerParams = samplers[s].s,
|
||||||
};
|
};
|
||||||
@@ -930,27 +954,6 @@ 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));
|
||||||
@@ -959,7 +962,7 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
|
|||||||
void MetalDriver::compilePrograms(CompilerPriorityQueue priority,
|
void MetalDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
scheduleCallback(handler, user, callback);
|
mContext->shaderCompiler->notifyWhenAllProgramsAreReady(handler, callback, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1376,51 +1379,65 @@ void MetalDriver::blit(TargetBufferFlags buffers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
||||||
// All of the id<MTLSamplerState> objects have already been bound to the argument buffer.
|
// All the id<MTLSamplerState> objects have already been bound to the argument buffer.
|
||||||
// Here we bind any textures that were unable to be bound in updateSamplerGroup.
|
// Here we bind all the textures.
|
||||||
|
|
||||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(mContext);
|
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(mContext);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
// Verify that all the textures in the sampler group are still alive.
|
||||||
// In debug builds, verify that all the textures in the sampler group are still alive.
|
|
||||||
// These bugs lead to memory corruption and can be difficult to track down.
|
// These bugs lead to memory corruption and can be difficult to track down.
|
||||||
const auto& handles = samplerGroup->getTextureHandles();
|
const auto& handles = samplerGroup->getTextureHandles();
|
||||||
for (size_t s = 0; s < handles.size(); s++) {
|
for (size_t s = 0; s < handles.size(); s++) {
|
||||||
if (!handles[s]) {
|
if (!handles[s]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto iter = mContext->textures.find(handle_cast<MetalTexture>(handles[s]));
|
// The difference between this check and the one below is that in release, we do this for
|
||||||
|
// only a set number of recently freed textures, while the debug check is exhaustive.
|
||||||
|
auto* metalTexture = handle_cast<MetalTexture>(handles[s]);
|
||||||
|
metalTexture->checkUseAfterFree(samplerGroup->debugName.c_str(), s);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto iter = mContext->textures.find(metalTexture);
|
||||||
if (iter == mContext->textures.end()) {
|
if (iter == mContext->textures.end()) {
|
||||||
utils::slog.e << "finalizeSamplerGroup: texture #"
|
utils::slog.e << "finalizeSamplerGroup: texture #"
|
||||||
<< (int) s << " is dead, texture handle = "
|
<< (int) s << " is dead, texture handle = "
|
||||||
<< handles[s] << utils::io::endl;
|
<< handles[s] << utils::io::endl;
|
||||||
}
|
}
|
||||||
assert_invariant(iter != mContext->textures.end());
|
assert_invariant(iter != mContext->textures.end());
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t binding = 0; binding < samplerGroup->size; binding++) {
|
|
||||||
auto [th, t] = samplerGroup->getFinalizedTexture(binding);
|
|
||||||
|
|
||||||
// This may be an external texture, in which case we can't cache the id<MTLTexture>, we
|
|
||||||
// need to refetch it in case the external image has changed.
|
|
||||||
bool isExternalImage = false;
|
|
||||||
if (th) {
|
|
||||||
auto* texture = handle_cast<MetalTexture>(th);
|
|
||||||
isExternalImage = texture->target == SamplerType::SAMPLER_EXTERNAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If t is non-nil, then we've already finalized this texture.
|
utils::FixedCapacityVector<id<MTLTexture>> newTextures(samplerGroup->size, nil);
|
||||||
if (t && !isExternalImage) {
|
for (size_t binding = 0; binding < samplerGroup->size; binding++) {
|
||||||
|
auto [th, _] = samplerGroup->getFinalizedTexture(binding);
|
||||||
|
|
||||||
|
if (!th) {
|
||||||
|
// Bind an empty texture.
|
||||||
|
newTextures[binding] = getOrCreateEmptyTexture(mContext);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's possible that some texture handles are null, but we should have already handled
|
|
||||||
// these inside updateSamplerGroup by binding an "empty" texture.
|
|
||||||
assert_invariant(th);
|
assert_invariant(th);
|
||||||
auto* texture = handle_cast<MetalTexture>(th);
|
auto* texture = handle_cast<MetalTexture>(th);
|
||||||
|
|
||||||
// Determine if this SamplerGroup needs mutation.
|
// External images
|
||||||
|
if (texture->target == SamplerType::SAMPLER_EXTERNAL) {
|
||||||
|
if (texture->externalImage.isValid()) {
|
||||||
|
id<MTLTexture> mtlTexture = texture->externalImage.getMetalTextureForDraw();
|
||||||
|
assert_invariant(mtlTexture);
|
||||||
|
newTextures[binding] = mtlTexture;
|
||||||
|
} else {
|
||||||
|
// Bind an empty texture.
|
||||||
|
newTextures[binding] = getOrCreateEmptyTexture(mContext);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newTextures[binding] = texture->getMtlTextureForRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::equal(newTextures.begin(), newTextures.end(), samplerGroup->textures.begin())) {
|
||||||
|
// One or more of the id<MTLTexture>s has changed.
|
||||||
|
// First, determine if this SamplerGroup needs mutation.
|
||||||
// We can't just simply mutate the SamplerGroup, since it could currently be in use by the
|
// We can't just simply mutate the SamplerGroup, since it could currently be in use by the
|
||||||
// GPU from a prior render pass.
|
// GPU from a prior render pass.
|
||||||
// If the SamplerGroup does need mutation, then there's two cases:
|
// If the SamplerGroup does need mutation, then there's two cases:
|
||||||
@@ -1428,29 +1445,17 @@ void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
|||||||
// draw call). We're free to mutate it.
|
// draw call). We're free to mutate it.
|
||||||
// 2. The SamplerGroup is finalized. We must call mutate(), which will create a new argument
|
// 2. The SamplerGroup is finalized. We must call mutate(), which will create a new argument
|
||||||
// buffer that we can then mutate freely.
|
// buffer that we can then mutate freely.
|
||||||
// TODO: don't just always call mutate, check to see if the texture is actually different.
|
|
||||||
|
|
||||||
if (samplerGroup->isFinalized()) {
|
if (samplerGroup->isFinalized()) {
|
||||||
samplerGroup->mutate(cmdBuffer);
|
samplerGroup->mutate(cmdBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// External images
|
for (size_t binding = 0; binding < samplerGroup->size; binding++) {
|
||||||
if (texture->target == SamplerType::SAMPLER_EXTERNAL) {
|
samplerGroup->setFinalizedTexture(binding, newTextures[binding]);
|
||||||
if (texture->externalImage.isValid()) {
|
|
||||||
id<MTLTexture> mtlTexture = texture->externalImage.getMetalTextureForDraw();
|
|
||||||
assert_invariant(mtlTexture);
|
|
||||||
samplerGroup->setFinalizedTexture(binding, mtlTexture);
|
|
||||||
} else {
|
|
||||||
// Bind an empty texture.
|
|
||||||
samplerGroup->setFinalizedTexture(binding, getOrCreateEmptyTexture(mContext));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplerGroup->setFinalizedTexture(binding, texture->getMtlTextureForRead());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
samplerGroup->finalize();
|
samplerGroup->finalize();
|
||||||
|
}
|
||||||
|
|
||||||
// At this point, all the id<MTLTextures> should be set to valid textures. Some of them will be
|
// At this point, all the id<MTLTextures> should be set to valid textures. Some of them will be
|
||||||
// the "empty" texture. Per Apple documentation, the useResource method must be called once per
|
// the "empty" texture. Per Apple documentation, the useResource method must be called once per
|
||||||
@@ -1473,14 +1478,19 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
|||||||
auto program = handle_cast<MetalProgram>(ps.program);
|
auto program = handle_cast<MetalProgram>(ps.program);
|
||||||
const auto& rs = ps.rasterState;
|
const auto& rs = ps.rasterState;
|
||||||
|
|
||||||
|
// This might block until the shader compilation has finished.
|
||||||
|
auto functions = program->getFunctions();
|
||||||
|
|
||||||
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
||||||
// during the draw call when the program is invalid. The shader compile error has already been
|
// during the draw call when the program is invalid. The shader compile error has already been
|
||||||
// dumped to the console at this point, so it's fine to simply return early.
|
// dumped to the console at this point, so it's fine to simply return early.
|
||||||
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!program->isValid)) {
|
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!functions)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_PRECONDITION(program->isValid, "Attempting to draw with an invalid Metal program.");
|
ASSERT_PRECONDITION(bool(functions), "Attempting to draw with an invalid Metal program.");
|
||||||
|
|
||||||
|
auto [fragment, vertex] = functions.getRasterFunctions();
|
||||||
|
|
||||||
// Pipeline state
|
// Pipeline state
|
||||||
MTLPixelFormat colorPixelFormat[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = { MTLPixelFormatInvalid };
|
MTLPixelFormat colorPixelFormat[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = { MTLPixelFormatInvalid };
|
||||||
@@ -1503,8 +1513,8 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
|||||||
assert_invariant(isMetalFormatStencil(stencilPixelFormat));
|
assert_invariant(isMetalFormatStencil(stencilPixelFormat));
|
||||||
}
|
}
|
||||||
MetalPipelineState pipelineState {
|
MetalPipelineState pipelineState {
|
||||||
.vertexFunction = program->vertexFunction,
|
.vertexFunction = vertex,
|
||||||
.fragmentFunction = program->fragmentFunction,
|
.fragmentFunction = fragment,
|
||||||
.vertexDescription = primitive->vertexDescription,
|
.vertexDescription = primitive->vertexDescription,
|
||||||
.colorAttachmentPixelFormat = {
|
.colorAttachmentPixelFormat = {
|
||||||
colorPixelFormat[0],
|
colorPixelFormat[0],
|
||||||
@@ -1649,7 +1659,7 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
|||||||
if (!samplerGroup) {
|
if (!samplerGroup) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& stageFlags = program->samplerGroupInfo[s].stageFlags;
|
const auto& stageFlags = program->getSamplerGroupInfo()[s].stageFlags;
|
||||||
if (stageFlags == ShaderStageFlags::NONE) {
|
if (stageFlags == ShaderStageFlags::NONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1676,26 +1686,23 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
|||||||
|
|
||||||
// Bind the user vertex buffers.
|
// Bind the user vertex buffers.
|
||||||
|
|
||||||
MetalBuffer* buffers[MAX_VERTEX_BUFFER_COUNT] = {};
|
MetalBuffer* vertexBuffers[MAX_VERTEX_BUFFER_COUNT] = {};
|
||||||
size_t vertexBufferOffsets[MAX_VERTEX_BUFFER_COUNT] = {};
|
size_t vertexBufferOffsets[MAX_VERTEX_BUFFER_COUNT] = {};
|
||||||
size_t bufferIndex = 0;
|
size_t maxBufferIndex = 0;
|
||||||
|
|
||||||
auto vb = primitive->vertexBuffer;
|
auto vb = primitive->vertexBuffer;
|
||||||
for (uint32_t attributeIndex = 0; attributeIndex < vb->attributes.size(); attributeIndex++) {
|
for (auto m : primitive->bufferMapping) {
|
||||||
const auto& attribute = vb->attributes[attributeIndex];
|
assert_invariant(
|
||||||
if (attribute.buffer == Attribute::BUFFER_UNUSED) {
|
m.bufferArgumentIndex >= USER_VERTEX_BUFFER_BINDING_START &&
|
||||||
continue;
|
m.bufferArgumentIndex < USER_VERTEX_BUFFER_BINDING_START + MAX_VERTEX_BUFFER_COUNT);
|
||||||
|
size_t vertexBufferIndex = m.bufferArgumentIndex - USER_VERTEX_BUFFER_BINDING_START;
|
||||||
|
vertexBuffers[vertexBufferIndex] = vb->buffers[m.sourceBufferIndex];
|
||||||
|
maxBufferIndex = std::max(maxBufferIndex, vertexBufferIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_invariant(vb->buffers[attribute.buffer]);
|
const auto bufferCount = maxBufferIndex + 1;
|
||||||
buffers[bufferIndex] = vb->buffers[attribute.buffer];
|
|
||||||
vertexBufferOffsets[bufferIndex] = attribute.offset;
|
|
||||||
bufferIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto bufferCount = bufferIndex;
|
|
||||||
MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
|
MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
|
||||||
USER_VERTEX_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX, buffers,
|
USER_VERTEX_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX, vertexBuffers,
|
||||||
vertexBufferOffsets, bufferCount);
|
vertexBufferOffsets, bufferCount);
|
||||||
|
|
||||||
// Bind the zero buffer, used for missing vertex attributes.
|
// Bind the zero buffer, used for missing vertex attributes.
|
||||||
@@ -1722,21 +1729,26 @@ void MetalDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGro
|
|||||||
|
|
||||||
auto mtlProgram = handle_cast<MetalProgram>(program);
|
auto mtlProgram = handle_cast<MetalProgram>(program);
|
||||||
|
|
||||||
|
// This might block until the shader compilation has finished.
|
||||||
|
auto functions = mtlProgram->getFunctions();
|
||||||
|
|
||||||
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
||||||
// during the draw call when the program is invalid. The shader compile error has already been
|
// during the draw call when the program is invalid. The shader compile error has already been
|
||||||
// dumped to the console at this point, so it's fine to simply return early.
|
// dumped to the console at this point, so it's fine to simply return early.
|
||||||
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!mtlProgram->isValid)) {
|
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!functions)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_invariant(mtlProgram->isValid && mtlProgram->computeFunction);
|
auto compute = functions.getComputeFunction();
|
||||||
|
|
||||||
|
assert_invariant(bool(functions) && compute);
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> computeEncoder =
|
id<MTLComputeCommandEncoder> computeEncoder =
|
||||||
[getPendingCommandBuffer(mContext) computeCommandEncoder];
|
[getPendingCommandBuffer(mContext) computeCommandEncoder];
|
||||||
|
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
id<MTLComputePipelineState> computePipelineState =
|
id<MTLComputePipelineState> computePipelineState =
|
||||||
[mContext->device newComputePipelineStateWithFunction:mtlProgram->computeFunction
|
[mContext->device newComputePipelineStateWithFunction:compute
|
||||||
error:&error];
|
error:&error];
|
||||||
if (error) {
|
if (error) {
|
||||||
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
|
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "private/backend/SamplerGroup.h"
|
#include "private/backend/SamplerGroup.h"
|
||||||
|
|
||||||
#include <utils/bitset.h>
|
#include <utils/bitset.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ public:
|
|||||||
id<MTLTexture> acquireDrawable();
|
id<MTLTexture> acquireDrawable();
|
||||||
|
|
||||||
id<MTLTexture> acquireDepthTexture();
|
id<MTLTexture> acquireDepthTexture();
|
||||||
|
id<MTLTexture> acquireStencilTexture();
|
||||||
|
|
||||||
void releaseDrawable();
|
void releaseDrawable();
|
||||||
|
|
||||||
@@ -94,12 +96,16 @@ private:
|
|||||||
void scheduleFrameScheduledCallback();
|
void scheduleFrameScheduledCallback();
|
||||||
void scheduleFrameCompletedCallback();
|
void scheduleFrameCompletedCallback();
|
||||||
|
|
||||||
|
static MTLPixelFormat decideDepthStencilFormat(uint64_t flags);
|
||||||
|
void ensureDepthStencilTexture();
|
||||||
|
|
||||||
MetalContext& context;
|
MetalContext& context;
|
||||||
id<CAMetalDrawable> drawable = nil;
|
id<CAMetalDrawable> drawable = nil;
|
||||||
id<MTLTexture> depthTexture = nil;
|
id<MTLTexture> depthStencilTexture = nil;
|
||||||
id<MTLTexture> headlessDrawable = nil;
|
id<MTLTexture> headlessDrawable = nil;
|
||||||
NSUInteger headlessWidth;
|
MTLPixelFormat depthStencilFormat = MTLPixelFormatInvalid;
|
||||||
NSUInteger headlessHeight;
|
NSUInteger headlessWidth = 0;
|
||||||
|
NSUInteger headlessHeight = 0;
|
||||||
CAMetalLayer* layer = nullptr;
|
CAMetalLayer* layer = nullptr;
|
||||||
MetalExternalImage externalImage;
|
MetalExternalImage externalImage;
|
||||||
SwapChainType type;
|
SwapChainType type;
|
||||||
@@ -154,6 +160,7 @@ struct MetalIndexBuffer : public HwIndexBuffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MetalRenderPrimitive : public HwRenderPrimitive {
|
struct MetalRenderPrimitive : public HwRenderPrimitive {
|
||||||
|
MetalRenderPrimitive();
|
||||||
void setBuffers(MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer);
|
void setBuffers(MetalVertexBuffer* vertexBuffer, MetalIndexBuffer* indexBuffer);
|
||||||
// The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak".
|
// The pointers to MetalVertexBuffer and MetalIndexBuffer are "weak".
|
||||||
// The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive.
|
// The MetalVertexBuffer and MetalIndexBuffer must outlive the MetalRenderPrimitive.
|
||||||
@@ -163,18 +170,35 @@ struct MetalRenderPrimitive : public HwRenderPrimitive {
|
|||||||
|
|
||||||
// This struct is used to create the pipeline description to describe vertex assembly.
|
// This struct is used to create the pipeline description to describe vertex assembly.
|
||||||
VertexDescription vertexDescription = {};
|
VertexDescription vertexDescription = {};
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
uint8_t sourceBufferIndex = 0;
|
||||||
|
uint8_t stride = 0;
|
||||||
|
// maps to ->
|
||||||
|
uint8_t bufferArgumentIndex = 0;
|
||||||
|
|
||||||
|
Entry(uint8_t sourceBufferIndex, uint8_t stride, uint8_t bufferArgumentIndex)
|
||||||
|
: sourceBufferIndex(sourceBufferIndex),
|
||||||
|
stride(stride),
|
||||||
|
bufferArgumentIndex(bufferArgumentIndex) {}
|
||||||
|
};
|
||||||
|
utils::FixedCapacityVector<Entry> bufferMapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MetalProgram : public HwProgram {
|
class MetalProgram : public HwProgram {
|
||||||
MetalProgram(id<MTLDevice> device, const Program& program) noexcept;
|
public:
|
||||||
|
MetalProgram(MetalContext& context, Program&& program) noexcept;
|
||||||
|
|
||||||
id<MTLFunction> vertexFunction;
|
const MetalShaderCompiler::MetalFunctionBundle& getFunctions();
|
||||||
id<MTLFunction> fragmentFunction;
|
const Program::SamplerGroupInfo& getSamplerGroupInfo() { return samplerGroupInfo; }
|
||||||
id<MTLFunction> computeFunction;
|
|
||||||
|
private:
|
||||||
|
void initialize();
|
||||||
|
|
||||||
Program::SamplerGroupInfo samplerGroupInfo;
|
Program::SamplerGroupInfo samplerGroupInfo;
|
||||||
|
MetalContext& mContext;
|
||||||
bool isValid = false;
|
MetalShaderCompiler::MetalFunctionBundle mFunctionBundle;
|
||||||
|
MetalShaderCompiler::program_token_t mToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PixelBufferShape {
|
struct PixelBufferShape {
|
||||||
@@ -217,21 +241,14 @@ 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. 3 actions update the range of LODs available:
|
// reading. 4 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
|
||||||
// The range of available mips can only increase, never decrease.
|
// - calling setMinMaxLevels
|
||||||
// A texture's available mips are consistent throughout a render pass.
|
// A texture's available mips are consistent throughout a render pass.
|
||||||
void updateLodRange(uint32_t level);
|
void setLodRange(uint16_t minLevel, uint16_t maxLevel);
|
||||||
void updateLodRange(uint32_t minLevel, uint32_t maxLevel);
|
void extendLodRangeTo(uint16_t level);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
@@ -245,6 +262,26 @@ public:
|
|||||||
|
|
||||||
MTLPixelFormat devicePixelFormat;
|
MTLPixelFormat devicePixelFormat;
|
||||||
|
|
||||||
|
// Frees memory associated with this texture and marks it as "terminated".
|
||||||
|
// Used to track "use after free" scenario.
|
||||||
|
void terminate() noexcept;
|
||||||
|
bool isTerminated() const noexcept { return terminated; }
|
||||||
|
inline void checkUseAfterFree(const char* samplerGroupDebugName, size_t textureIndex) const {
|
||||||
|
if (UTILS_LIKELY(!isTerminated())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSString* reason =
|
||||||
|
[NSString stringWithFormat:
|
||||||
|
@"Filament Metal texture use after free, sampler group = "
|
||||||
|
@"%s, texture index = %zu",
|
||||||
|
samplerGroupDebugName, textureIndex];
|
||||||
|
NSException* useAfterFreeException =
|
||||||
|
[NSException exceptionWithName:@"MetalTextureUseAfterFree"
|
||||||
|
reason:reason
|
||||||
|
userInfo:nil];
|
||||||
|
[useAfterFreeException raise];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
void loadSlice(uint32_t level, MTLRegion region, uint32_t byteOffset, uint32_t slice,
|
||||||
PixelBufferDescriptor const& data) noexcept;
|
PixelBufferDescriptor const& data) noexcept;
|
||||||
@@ -261,14 +298,17 @@ private:
|
|||||||
id<MTLTexture> swizzledTextureView = nil;
|
id<MTLTexture> swizzledTextureView = nil;
|
||||||
id<MTLTexture> lodTextureView = nil;
|
id<MTLTexture> lodTextureView = nil;
|
||||||
|
|
||||||
uint32_t minLod = UINT_MAX;
|
uint16_t minLod = std::numeric_limits<uint16_t>::max();
|
||||||
uint32_t maxLod = 0;
|
uint16_t maxLod = 0;
|
||||||
|
|
||||||
|
bool terminated = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MetalSamplerGroup : public HwSamplerGroup {
|
class MetalSamplerGroup : public HwSamplerGroup {
|
||||||
public:
|
public:
|
||||||
explicit MetalSamplerGroup(size_t size) noexcept
|
explicit MetalSamplerGroup(size_t size, utils::FixedSizeString<32> name) noexcept
|
||||||
: size(size),
|
: size(size),
|
||||||
|
debugName(name),
|
||||||
textureHandles(size, Handle<HwTexture>()),
|
textureHandles(size, Handle<HwTexture>()),
|
||||||
textures(size, nil),
|
textures(size, nil),
|
||||||
samplers(size, nil) {}
|
samplers(size, nil) {}
|
||||||
@@ -278,12 +318,10 @@ public:
|
|||||||
textureHandles[index] = th;
|
textureHandles[index] = th;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// This method is only used for debugging, to ensure all texture handles are alive.
|
// This method is only used for debugging, to ensure all texture handles are alive.
|
||||||
const auto& getTextureHandles() const {
|
const auto& getTextureHandles() const {
|
||||||
return textureHandles;
|
return textureHandles;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Encode a MTLTexture into this SamplerGroup at the given index.
|
// Encode a MTLTexture into this SamplerGroup at the given index.
|
||||||
inline void setFinalizedTexture(size_t index, id<MTLTexture> t) {
|
inline void setFinalizedTexture(size_t index, id<MTLTexture> t) {
|
||||||
@@ -329,6 +367,7 @@ public:
|
|||||||
void useResources(id<MTLRenderCommandEncoder> renderPassEncoder);
|
void useResources(id<MTLRenderCommandEncoder> renderPassEncoder);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
utils::FixedSizeString<32> debugName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags)
|
MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags)
|
||||||
: context(context), layer(nativeWindow), externalImage(context),
|
: context(context),
|
||||||
|
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||||
|
layer(nativeWindow),
|
||||||
|
externalImage(context),
|
||||||
type(SwapChainType::CAMETALLAYER) {
|
type(SwapChainType::CAMETALLAYER) {
|
||||||
|
|
||||||
if (!(flags & SwapChain::CONFIG_TRANSPARENT) && !nativeWindow.opaque) {
|
if (!(flags & SwapChain::CONFIG_TRANSPARENT) && !nativeWindow.opaque) {
|
||||||
@@ -79,17 +82,30 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags)
|
MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags)
|
||||||
: context(context), headlessWidth(width), headlessHeight(height), externalImage(context),
|
: context(context),
|
||||||
type(SwapChainType::HEADLESS) { }
|
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||||
|
headlessWidth(width),
|
||||||
|
headlessHeight(height),
|
||||||
|
externalImage(context),
|
||||||
|
type(SwapChainType::HEADLESS) {}
|
||||||
|
|
||||||
MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags)
|
MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags)
|
||||||
: context(context), externalImage(context), type(SwapChainType::CVPIXELBUFFERREF) {
|
: context(context),
|
||||||
|
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||||
|
externalImage(context),
|
||||||
|
type(SwapChainType::CVPIXELBUFFERREF) {
|
||||||
assert_invariant(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
|
assert_invariant(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
|
||||||
MetalExternalImage::assertWritableImage(pixelBuffer);
|
MetalExternalImage::assertWritableImage(pixelBuffer);
|
||||||
externalImage.set(pixelBuffer);
|
externalImage.set(pixelBuffer);
|
||||||
assert_invariant(externalImage.isValid());
|
assert_invariant(externalImage.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MTLPixelFormat MetalSwapChain::decideDepthStencilFormat(uint64_t flags) {
|
||||||
|
// These formats are supported on all devices, both iOS and macOS.
|
||||||
|
return flags & SwapChain::CONFIG_HAS_STENCIL_BUFFER ? MTLPixelFormatDepth32Float_Stencil8
|
||||||
|
: MTLPixelFormatDepth32Float;
|
||||||
|
}
|
||||||
|
|
||||||
MetalSwapChain::~MetalSwapChain() {
|
MetalSwapChain::~MetalSwapChain() {
|
||||||
externalImage.set(nullptr);
|
externalImage.set(nullptr);
|
||||||
}
|
}
|
||||||
@@ -156,37 +172,40 @@ void MetalSwapChain::releaseDrawable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
|
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
|
||||||
if (depthTexture) {
|
ensureDepthStencilTexture();
|
||||||
// If the surface size has changed, we'll need to allocate a new depth texture.
|
assert_invariant(depthStencilTexture);
|
||||||
if (depthTexture.width != getSurfaceWidth() ||
|
return depthStencilTexture;
|
||||||
depthTexture.height != getSurfaceHeight()) {
|
}
|
||||||
depthTexture = nil;
|
|
||||||
|
id<MTLTexture> MetalSwapChain::acquireStencilTexture() {
|
||||||
|
if (!isMetalFormatStencil(depthStencilFormat)) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
ensureDepthStencilTexture();
|
||||||
|
assert_invariant(depthStencilTexture);
|
||||||
|
return depthStencilTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalSwapChain::ensureDepthStencilTexture() {
|
||||||
|
NSUInteger width = getSurfaceWidth();
|
||||||
|
NSUInteger height = getSurfaceHeight();
|
||||||
|
if (UTILS_LIKELY(depthStencilTexture)) {
|
||||||
|
// If the surface size has changed, we'll need to allocate a new depth/stencil texture.
|
||||||
|
if (UTILS_UNLIKELY(
|
||||||
|
depthStencilTexture.width != width || depthStencilTexture.height != height)) {
|
||||||
|
depthStencilTexture = nil;
|
||||||
} else {
|
} else {
|
||||||
return depthTexture;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MTLPixelFormat depthFormat =
|
|
||||||
#if defined(IOS)
|
|
||||||
MTLPixelFormatDepth32Float;
|
|
||||||
#else
|
|
||||||
context.device.depth24Stencil8PixelFormatSupported ?
|
|
||||||
MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const NSUInteger width = getSurfaceWidth();
|
|
||||||
const NSUInteger height = getSurfaceHeight();
|
|
||||||
MTLTextureDescriptor* descriptor =
|
MTLTextureDescriptor* descriptor =
|
||||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:depthFormat
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:depthStencilFormat
|
||||||
width:width
|
width:width
|
||||||
height:height
|
height:height
|
||||||
mipmapped:NO];
|
mipmapped:NO];
|
||||||
descriptor.usage = MTLTextureUsageRenderTarget;
|
descriptor.usage = MTLTextureUsageRenderTarget;
|
||||||
descriptor.resourceOptions = MTLResourceStorageModePrivate;
|
descriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||||
|
depthStencilTexture = [context.device newTextureWithDescriptor:descriptor];
|
||||||
depthTexture = [context.device newTextureWithDescriptor:descriptor];
|
|
||||||
|
|
||||||
return depthTexture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalSwapChain::setFrameScheduledCallback(FrameScheduledCallback callback, void* user) {
|
void MetalSwapChain::setFrameScheduledCallback(FrameScheduledCallback callback, void* user) {
|
||||||
@@ -280,6 +299,9 @@ MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uin
|
|||||||
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
||||||
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
||||||
|
|
||||||
|
MetalRenderPrimitive::MetalRenderPrimitive()
|
||||||
|
: bufferMapping(utils::FixedCapacityVector<Entry>::with_capacity(MAX_VERTEX_BUFFER_COUNT)) {}
|
||||||
|
|
||||||
void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalIndexBuffer*
|
void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalIndexBuffer*
|
||||||
indexBuffer) {
|
indexBuffer) {
|
||||||
this->vertexBuffer = vertexBuffer;
|
this->vertexBuffer = vertexBuffer;
|
||||||
@@ -287,118 +309,94 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
|
|||||||
|
|
||||||
const size_t attributeCount = vertexBuffer->attributes.size();
|
const size_t attributeCount = vertexBuffer->attributes.size();
|
||||||
|
|
||||||
|
auto& mapping = bufferMapping;
|
||||||
|
mapping.clear();
|
||||||
vertexDescription = {};
|
vertexDescription = {};
|
||||||
|
|
||||||
// Each attribute gets its own vertex buffer, starting at logical buffer 1.
|
// Set the layout for the zero buffer, which unused attributes are mapped to.
|
||||||
uint32_t bufferIndex = 1;
|
vertexDescription.layouts[ZERO_VERTEX_BUFFER_LOGICAL_INDEX] = {
|
||||||
|
.step = MTLVertexStepFunctionConstant, .stride = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
// Here we map each source buffer to a Metal buffer argument.
|
||||||
|
// Each attribute has a source buffer, offset, and stride.
|
||||||
|
// Two source buffers with the same index and stride can share the same Metal buffer argument
|
||||||
|
// index.
|
||||||
|
//
|
||||||
|
// The source buffer is the buffer index that the Filament client sets.
|
||||||
|
// * source buffer
|
||||||
|
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12)
|
||||||
|
// .attribute(VertexAttribute::UV, 0, VertexBuffer::AttributeType::HALF2, 8, 12)
|
||||||
|
// .attribute(VertexAttribute::COLOR, 1, VertexBuffer::AttributeType::UBYTE4, 0, 4)
|
||||||
|
|
||||||
|
auto allocateOrGetBufferArgumentIndex =
|
||||||
|
[&mapping, currentBufferArgumentIndex = USER_VERTEX_BUFFER_BINDING_START, this](
|
||||||
|
auto sourceBuffer, auto sourceBufferStride) mutable -> uint8_t {
|
||||||
|
auto match = [&](const auto& e) {
|
||||||
|
return e.sourceBufferIndex == sourceBuffer && e.stride == sourceBufferStride;
|
||||||
|
};
|
||||||
|
if (auto it = std::find_if(mapping.begin(), mapping.end(), match); it != mapping.end()) {
|
||||||
|
return it->bufferArgumentIndex;
|
||||||
|
} else {
|
||||||
|
auto bufferArgumentIndex = currentBufferArgumentIndex++;
|
||||||
|
mapping.emplace_back(sourceBuffer, sourceBufferStride, bufferArgumentIndex);
|
||||||
|
vertexDescription.layouts[bufferArgumentIndex] = {
|
||||||
|
.step = MTLVertexStepFunctionPerVertex, .stride = sourceBufferStride
|
||||||
|
};
|
||||||
|
return bufferArgumentIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (uint32_t attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) {
|
for (uint32_t attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) {
|
||||||
const auto& attribute = vertexBuffer->attributes[attributeIndex];
|
const auto& attribute = vertexBuffer->attributes[attributeIndex];
|
||||||
if (attribute.buffer == Attribute::BUFFER_UNUSED) {
|
|
||||||
const uint8_t flags = attribute.flags;
|
|
||||||
const MTLVertexFormat format = (flags & Attribute::FLAG_INTEGER_TARGET) ?
|
|
||||||
MTLVertexFormatUInt4 : MTLVertexFormatFloat4;
|
|
||||||
|
|
||||||
// If the attribute is not enabled, bind it to the zero buffer. It's a Metal error for a
|
// If the attribute is unused, bind it to the zero buffer. It's a Metal error for a shader
|
||||||
// shader to read from missing vertex attributes.
|
// to read from missing vertex attributes.
|
||||||
|
if (attribute.buffer == Attribute::BUFFER_UNUSED) {
|
||||||
|
const MTLVertexFormat format = (attribute.flags & Attribute::FLAG_INTEGER_TARGET)
|
||||||
|
? MTLVertexFormatUInt4
|
||||||
|
: MTLVertexFormatFloat4;
|
||||||
vertexDescription.attributes[attributeIndex] = {
|
vertexDescription.attributes[attributeIndex] = {
|
||||||
.format = format,
|
.format = format, .buffer = ZERO_VERTEX_BUFFER_LOGICAL_INDEX, .offset = 0
|
||||||
.buffer = ZERO_VERTEX_BUFFER_LOGICAL_INDEX,
|
|
||||||
.offset = 0
|
|
||||||
};
|
|
||||||
vertexDescription.layouts[ZERO_VERTEX_BUFFER_LOGICAL_INDEX] = {
|
|
||||||
.step = MTLVertexStepFunctionConstant,
|
|
||||||
.stride = 16
|
|
||||||
};
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexDescription.attributes[attributeIndex] = {
|
// Map the source buffer and stride of this attribute to a Metal buffer argument.
|
||||||
.format = getMetalFormat(attribute.type,
|
auto bufferArgumentIndex =
|
||||||
attribute.flags & Attribute::FLAG_NORMALIZED),
|
allocateOrGetBufferArgumentIndex(attribute.buffer, attribute.stride);
|
||||||
.buffer = bufferIndex,
|
|
||||||
.offset = 0
|
|
||||||
};
|
|
||||||
vertexDescription.layouts[bufferIndex] = {
|
|
||||||
.step = MTLVertexStepFunctionPerVertex,
|
|
||||||
.stride = attribute.stride
|
|
||||||
};
|
|
||||||
|
|
||||||
bufferIndex++;
|
vertexDescription.attributes[attributeIndex] = {
|
||||||
|
.format = getMetalFormat(
|
||||||
|
attribute.type, attribute.flags & Attribute::FLAG_NORMALIZED),
|
||||||
|
.buffer = uint32_t(bufferArgumentIndex),
|
||||||
|
.offset = attribute.offset
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcept
|
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
|
||||||
: HwProgram(program.getName()), vertexFunction(nil), fragmentFunction(nil),
|
: HwProgram(program.getName()), mContext(context) {
|
||||||
computeFunction(nil), isValid(false) {
|
|
||||||
|
|
||||||
using MetalFunctionPtr = __strong id<MTLFunction>*;
|
|
||||||
|
|
||||||
static_assert(Program::SHADER_TYPE_COUNT == 3, "Only vertex, fragment, and/or compute shaders expected.");
|
|
||||||
MetalFunctionPtr shaderFunctions[3] = { &vertexFunction, &fragmentFunction, &computeFunction };
|
|
||||||
|
|
||||||
const auto& sources = program.getShadersSource();
|
|
||||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
|
||||||
const auto& source = sources[i];
|
|
||||||
// It's okay for some shaders to be empty, they shouldn't be used in any draw calls.
|
|
||||||
if (source.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_invariant( source[source.size() - 1] == '\0' );
|
|
||||||
|
|
||||||
// the shader string is null terminated and the length includes the null character
|
|
||||||
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
|
|
||||||
length:source.size() - 1
|
|
||||||
encoding:NSUTF8StringEncoding];
|
|
||||||
NSError* error = nil;
|
|
||||||
// When options is nil, Metal uses the most recent language version available.
|
|
||||||
id<MTLLibrary> library = [device newLibraryWithSource:objcSource
|
|
||||||
options:nil
|
|
||||||
error:&error];
|
|
||||||
if (library == nil) {
|
|
||||||
if (error) {
|
|
||||||
auto description =
|
|
||||||
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
utils::slog.w << description << utils::io::endl;
|
|
||||||
}
|
|
||||||
PANIC_LOG("Failed to compile Metal program.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MTLFunctionConstantValues* constants = [MTLFunctionConstantValues new];
|
|
||||||
auto const& specializationConstants = program.getSpecializationConstants();
|
|
||||||
for (auto const& sc : specializationConstants) {
|
|
||||||
const std::array<MTLDataType, 3> types{
|
|
||||||
MTLDataTypeInt, MTLDataTypeFloat, MTLDataTypeBool };
|
|
||||||
std::visit([&sc, constants, type = types[sc.value.index()]](auto&& arg) {
|
|
||||||
[constants setConstantValue:&arg
|
|
||||||
type:type
|
|
||||||
atIndex:sc.id];
|
|
||||||
}, sc.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLFunction> function = [library newFunctionWithName:@"main0"
|
|
||||||
constantValues:constants
|
|
||||||
error:&error];
|
|
||||||
if (!program.getName().empty()) {
|
|
||||||
function.label = @(program.getName().c_str());
|
|
||||||
}
|
|
||||||
assert_invariant(function);
|
|
||||||
*shaderFunctions[i] = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
UTILS_UNUSED_IN_RELEASE const bool isRasterizationProgram =
|
|
||||||
vertexFunction != nil && fragmentFunction != nil;
|
|
||||||
UTILS_UNUSED_IN_RELEASE const bool isComputeProgram = computeFunction != nil;
|
|
||||||
// The program must be either a rasterization program XOR a compute program.
|
|
||||||
assert_invariant(isRasterizationProgram != isComputeProgram);
|
|
||||||
|
|
||||||
// All stages of the program have compiled successfully, this is a valid program.
|
|
||||||
isValid = true;
|
|
||||||
|
|
||||||
// Save this program's SamplerGroupInfo, it's used during draw calls to bind sampler groups to
|
// Save this program's SamplerGroupInfo, it's used during draw calls to bind sampler groups to
|
||||||
// the appropriate stage(s).
|
// the appropriate stage(s).
|
||||||
samplerGroupInfo = program.getSamplerGroupInfo();
|
samplerGroupInfo = program.getSamplerGroupInfo();
|
||||||
|
|
||||||
|
mToken = context.shaderCompiler->createProgram(program.getName(), std::move(program));
|
||||||
|
assert_invariant(mToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MetalShaderCompiler::MetalFunctionBundle& MetalProgram::getFunctions() {
|
||||||
|
initialize();
|
||||||
|
return mFunctionBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalProgram::initialize() {
|
||||||
|
if (!mToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mFunctionBundle = mContext.shaderCompiler->getProgram(mToken);
|
||||||
|
assert_invariant(!mToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
|
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
|
||||||
@@ -513,7 +511,16 @@ 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;
|
||||||
updateLodRange(0, levels - 1);
|
setLodRange(0, levels - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalTexture::terminate() noexcept {
|
||||||
|
texture = nil;
|
||||||
|
swizzledTextureView = nil;
|
||||||
|
lodTextureView = nil;
|
||||||
|
msaaSidecar = nil;
|
||||||
|
externalImage.set(nullptr);
|
||||||
|
terminated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalTexture::~MetalTexture() {
|
MetalTexture::~MetalTexture() {
|
||||||
@@ -658,14 +665,14 @@ void MetalTexture::loadImage(uint32_t level, MTLRegion region, PixelBufferDescri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLodRange(level);
|
extendLodRangeTo(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];
|
||||||
updateLodRange(0, texture.mipmapLevelCount - 1);
|
setLodRange(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 +795,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::updateLodRange(uint32_t level) {
|
void MetalTexture::extendLodRangeTo(uint16_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::updateLodRange(uint32_t min, uint32_t max) {
|
void MetalTexture::setLodRange(uint16_t min, uint16_t max) {
|
||||||
assert_invariant(!isInRenderPass(&context));
|
assert_invariant(!isInRenderPass(&context));
|
||||||
assert_invariant(min <= max);
|
assert_invariant(min <= max);
|
||||||
minLod = std::min(minLod, min);
|
minLod = min;
|
||||||
maxLod = std::max(maxLod, max);
|
maxLod = max;
|
||||||
lodTextureView = nil;
|
lodTextureView = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1123,7 +1130,7 @@ MetalRenderTarget::Attachment MetalRenderTarget::getDepthAttachment() {
|
|||||||
MetalRenderTarget::Attachment MetalRenderTarget::getStencilAttachment() {
|
MetalRenderTarget::Attachment MetalRenderTarget::getStencilAttachment() {
|
||||||
Attachment result = stencil;
|
Attachment result = stencil;
|
||||||
if (defaultRenderTarget) {
|
if (defaultRenderTarget) {
|
||||||
// TODO: do we want the default SwapChain to have a default stencil buffer?
|
result.texture = context->currentDrawSwapChain->acquireStencilTexture();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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_FILAMENT_BACKEND_METAL_METALSHADERCOMPILER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_METAL_METALSHADERCOMPILER_H
|
||||||
|
|
||||||
|
#include "CompilerThreadPool.h"
|
||||||
|
|
||||||
|
#include "CallbackManager.h"
|
||||||
|
|
||||||
|
#include <backend/CallbackHandler.h>
|
||||||
|
#include <backend/Program.h>
|
||||||
|
|
||||||
|
#include <utils/CString.h>
|
||||||
|
|
||||||
|
#include <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class MetalDriver;
|
||||||
|
|
||||||
|
class MetalShaderCompiler {
|
||||||
|
struct MetalProgramToken;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class MetalFunctionBundle {
|
||||||
|
public:
|
||||||
|
MetalFunctionBundle() = default;
|
||||||
|
MetalFunctionBundle(id<MTLFunction> fragment, id<MTLFunction> vertex)
|
||||||
|
: functions{fragment, vertex} {
|
||||||
|
assert_invariant(fragment && vertex);
|
||||||
|
assert_invariant(fragment.functionType == MTLFunctionTypeFragment);
|
||||||
|
assert_invariant(vertex.functionType == MTLFunctionTypeVertex);
|
||||||
|
}
|
||||||
|
explicit MetalFunctionBundle(id<MTLFunction> compute) : functions{compute, nil} {
|
||||||
|
assert_invariant(compute);
|
||||||
|
assert_invariant(compute.functionType == MTLFunctionTypeKernel);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<id<MTLFunction>, id<MTLFunction>> getRasterFunctions() const noexcept {
|
||||||
|
assert_invariant(functions[0].functionType == MTLFunctionTypeFragment);
|
||||||
|
assert_invariant(functions[1].functionType == MTLFunctionTypeVertex);
|
||||||
|
return {functions[0], functions[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLFunction> getComputeFunction() const noexcept {
|
||||||
|
assert_invariant(functions[0].functionType == MTLFunctionTypeKernel);
|
||||||
|
return functions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const { return functions[0] != nil; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Can hold two functions, either:
|
||||||
|
// - fragment and vertex (for rasterization pipelines)
|
||||||
|
// - compute (for compute pipelines)
|
||||||
|
id<MTLFunction> functions[2] = {nil, nil};
|
||||||
|
};
|
||||||
|
|
||||||
|
using program_token_t = std::shared_ptr<MetalProgramToken>;
|
||||||
|
|
||||||
|
explicit MetalShaderCompiler(id<MTLDevice> device, MetalDriver& driver);
|
||||||
|
|
||||||
|
MetalShaderCompiler(MetalShaderCompiler const& rhs) = delete;
|
||||||
|
MetalShaderCompiler(MetalShaderCompiler&& rhs) = delete;
|
||||||
|
MetalShaderCompiler& operator=(MetalShaderCompiler const& rhs) = delete;
|
||||||
|
MetalShaderCompiler& operator=(MetalShaderCompiler&& rhs) = delete;
|
||||||
|
|
||||||
|
void init() noexcept;
|
||||||
|
void terminate() noexcept;
|
||||||
|
|
||||||
|
// Creates a program asynchronously
|
||||||
|
program_token_t createProgram(utils::CString const& name, Program&& program);
|
||||||
|
|
||||||
|
// Returns the functions, blocking if necessary. The Token is destroyed and becomes invalid.
|
||||||
|
MetalFunctionBundle getProgram(program_token_t& token);
|
||||||
|
|
||||||
|
// Destroys a valid token and all associated resources. Used to "cancel" a program compilation.
|
||||||
|
static void terminate(program_token_t& token);
|
||||||
|
|
||||||
|
void notifyWhenAllProgramsAreReady(
|
||||||
|
CallbackHandler* handler, CallbackHandler::Callback callback, void* user);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static MetalFunctionBundle compileProgram(const Program& program, id<MTLDevice> device);
|
||||||
|
|
||||||
|
CompilerThreadPool mCompilerThreadPool;
|
||||||
|
id<MTLDevice> mDevice;
|
||||||
|
CallbackManager mCallbackManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
|
#endif // TNT_FILAMENT_BACKEND_METAL_METALSHADERCOMPILER_H
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* 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 "MetalShaderCompiler.h"
|
||||||
|
|
||||||
|
#include "MetalDriver.h"
|
||||||
|
|
||||||
|
#include <backend/Program.h>
|
||||||
|
|
||||||
|
#include <utils/JobSystem.h>
|
||||||
|
#include <utils/Mutex.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
using namespace utils;
|
||||||
|
|
||||||
|
struct MetalShaderCompiler::MetalProgramToken : ProgramToken {
|
||||||
|
|
||||||
|
MetalProgramToken(MetalShaderCompiler& compiler) noexcept
|
||||||
|
: compiler(compiler) {
|
||||||
|
}
|
||||||
|
~MetalProgramToken() override;
|
||||||
|
|
||||||
|
void set(MetalFunctionBundle p) noexcept {
|
||||||
|
std::unique_lock const l(lock);
|
||||||
|
std::swap(program, p);
|
||||||
|
signaled = true;
|
||||||
|
cond.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalFunctionBundle get() const noexcept {
|
||||||
|
std::unique_lock l(lock);
|
||||||
|
cond.wait(l, [this](){ return signaled; });
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait() const noexcept {
|
||||||
|
std::unique_lock l(lock);
|
||||||
|
cond.wait(l, [this]() { return signaled; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isReady() const noexcept {
|
||||||
|
std::unique_lock l(lock);
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
return cond.wait_for(l, 0s, [this]() { return signaled; });
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalShaderCompiler& compiler;
|
||||||
|
CallbackManager::Handle handle{};
|
||||||
|
MetalFunctionBundle program{};
|
||||||
|
mutable utils::Mutex lock;
|
||||||
|
mutable utils::Condition cond;
|
||||||
|
bool signaled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
MetalShaderCompiler::MetalProgramToken::~MetalProgramToken() = default;
|
||||||
|
|
||||||
|
MetalShaderCompiler::MetalShaderCompiler(id<MTLDevice> device, MetalDriver& driver)
|
||||||
|
: mDevice(device),
|
||||||
|
mCallbackManager(driver) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalShaderCompiler::init() noexcept {
|
||||||
|
const uint32_t poolSize = 2;
|
||||||
|
mCompilerThreadPool.init(poolSize, []() {}, []() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalShaderCompiler::terminate() noexcept {
|
||||||
|
mCompilerThreadPool.terminate();
|
||||||
|
mCallbackManager.terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ MetalShaderCompiler::MetalFunctionBundle MetalShaderCompiler::compileProgram(
|
||||||
|
const Program& program, id<MTLDevice> device) {
|
||||||
|
std::array<id<MTLFunction>, Program::SHADER_TYPE_COUNT> functions = { nil };
|
||||||
|
const auto& sources = program.getShadersSource();
|
||||||
|
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||||
|
const auto& source = sources[i];
|
||||||
|
// It's okay for some shaders to be empty, they shouldn't be used in any draw calls.
|
||||||
|
if (source.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_invariant(source[source.size() - 1] == '\0');
|
||||||
|
|
||||||
|
// the shader string is null terminated and the length includes the null character
|
||||||
|
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
|
||||||
|
length:source.size() - 1
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
NSError* error = nil;
|
||||||
|
// When options is nil, Metal uses the most recent language version available.
|
||||||
|
id<MTLLibrary> library = [device newLibraryWithSource:objcSource
|
||||||
|
options:nil
|
||||||
|
error:&error];
|
||||||
|
if (library == nil) {
|
||||||
|
if (error) {
|
||||||
|
auto description =
|
||||||
|
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
utils::slog.w << description << utils::io::endl;
|
||||||
|
}
|
||||||
|
PANIC_LOG("Failed to compile Metal program.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLFunctionConstantValues* constants = [MTLFunctionConstantValues new];
|
||||||
|
auto const& specializationConstants = program.getSpecializationConstants();
|
||||||
|
for (auto const& sc : specializationConstants) {
|
||||||
|
const std::array<MTLDataType, 3> types{
|
||||||
|
MTLDataTypeInt, MTLDataTypeFloat, MTLDataTypeBool };
|
||||||
|
std::visit([&sc, constants, type = types[sc.value.index()]](auto&& arg) {
|
||||||
|
[constants setConstantValue:&arg
|
||||||
|
type:type
|
||||||
|
atIndex:sc.id];
|
||||||
|
}, sc.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLFunction> function = [library newFunctionWithName:@"main0"
|
||||||
|
constantValues:constants
|
||||||
|
error:&error];
|
||||||
|
if (!program.getName().empty()) {
|
||||||
|
function.label = @(program.getName().c_str());
|
||||||
|
}
|
||||||
|
assert_invariant(function);
|
||||||
|
functions[i] = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(Program::SHADER_TYPE_COUNT == 3,
|
||||||
|
"Only vertex, fragment, and/or compute shaders expected.");
|
||||||
|
id<MTLFunction> vertexFunction = functions[0];
|
||||||
|
id<MTLFunction> fragmentFunction = functions[1];
|
||||||
|
id<MTLFunction> computeFunction = functions[2];
|
||||||
|
const bool isRasterizationProgram = vertexFunction != nil && fragmentFunction != nil;
|
||||||
|
const bool isComputeProgram = computeFunction != nil;
|
||||||
|
// The program must be either a rasterization program XOR a compute program.
|
||||||
|
assert_invariant(isRasterizationProgram != isComputeProgram);
|
||||||
|
|
||||||
|
if (isRasterizationProgram) {
|
||||||
|
return {fragmentFunction, vertexFunction};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isComputeProgram) {
|
||||||
|
return MetalFunctionBundle{computeFunction};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalShaderCompiler::program_token_t MetalShaderCompiler::createProgram(
|
||||||
|
CString const& name, Program&& program) {
|
||||||
|
auto token = std::make_shared<MetalProgramToken>(*this);
|
||||||
|
|
||||||
|
token->handle = mCallbackManager.get();
|
||||||
|
|
||||||
|
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
|
||||||
|
mCompilerThreadPool.queue(priorityQueue, token,
|
||||||
|
[this, name, device = mDevice, program = std::move(program), token]() {
|
||||||
|
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||||
|
|
||||||
|
token->set(compiledProgram);
|
||||||
|
mCallbackManager.put(token->handle);
|
||||||
|
});
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalShaderCompiler::MetalFunctionBundle MetalShaderCompiler::getProgram(program_token_t& token) {
|
||||||
|
assert_invariant(token);
|
||||||
|
|
||||||
|
if (!token->isReady()) {
|
||||||
|
auto job = mCompilerThreadPool.dequeue(token);
|
||||||
|
if (job) {
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalShaderCompiler::MetalFunctionBundle program = token->get();
|
||||||
|
|
||||||
|
token = nullptr;
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void MetalShaderCompiler::terminate(program_token_t& token) {
|
||||||
|
assert_invariant(token);
|
||||||
|
|
||||||
|
auto job = token->compiler.mCompilerThreadPool.dequeue(token);
|
||||||
|
if (!job) {
|
||||||
|
// The job is being executed right now (or has already executed).
|
||||||
|
token->wait();
|
||||||
|
} else {
|
||||||
|
// The job has not executed yet.
|
||||||
|
token->compiler.mCallbackManager.put(token->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
token.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalShaderCompiler::notifyWhenAllProgramsAreReady(
|
||||||
|
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||||
|
mCallbackManager.setCallback(handler, callback, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
@@ -373,8 +373,11 @@ constexpr inline GLenum getCullingMode(CullingMode mode) noexcept {
|
|||||||
constexpr inline std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
constexpr inline std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
||||||
TextureFormat format) noexcept {
|
TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
|
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
|
||||||
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||||
|
case TextureFormat::SRGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||||
case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
case TextureFormat::SRGB8_A8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
|
case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
|
||||||
case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 };
|
case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 };
|
||||||
case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
|
case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "OpenGLBlobCache.h"
|
#include "OpenGLBlobCache.h"
|
||||||
|
|
||||||
|
#include "OpenGLContext.h"
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
|
|
||||||
@@ -28,17 +30,18 @@ struct OpenGLBlobCache::Blob {
|
|||||||
char data[];
|
char data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
|
||||||
Program const& program) noexcept {
|
: mCachingSupported(gl.gets.num_program_binary_formats >= 1) {
|
||||||
SYSTRACE_CALL();
|
}
|
||||||
|
|
||||||
if (!platform.hasBlobFunc()) {
|
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||||
|
Program const& program) const noexcept {
|
||||||
|
SYSTRACE_CALL();
|
||||||
|
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
||||||
// the key is never updated in that case
|
// the key is never updated in that case
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSTRACE_CONTEXT();
|
|
||||||
|
|
||||||
GLuint programId = 0;
|
GLuint programId = 0;
|
||||||
|
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
@@ -64,8 +67,10 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
|||||||
|
|
||||||
programId = glCreateProgram();
|
programId = glCreateProgram();
|
||||||
|
|
||||||
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glProgramBinary");
|
SYSTRACE_NAME("glProgramBinary");
|
||||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||||
|
}
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
|
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
|
||||||
// glProgramBinary can fail if for instance the driver has been updated
|
// glProgramBinary can fail if for instance the driver has been updated
|
||||||
@@ -85,19 +90,28 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
|||||||
|
|
||||||
void OpenGLBlobCache::insert(Platform& platform,
|
void OpenGLBlobCache::insert(Platform& platform,
|
||||||
BlobCacheKey const& key, GLuint program) noexcept {
|
BlobCacheKey const& key, GLuint program) noexcept {
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
|
||||||
SYSTRACE_CALL();
|
SYSTRACE_CALL();
|
||||||
if (platform.hasBlobFunc()) {
|
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
||||||
SYSTRACE_CONTEXT();
|
// the key is never updated in that case
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
GLenum format;
|
GLenum format;
|
||||||
GLint programBinarySize;
|
GLint programBinarySize = 0;
|
||||||
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glGetProgramiv");
|
SYSTRACE_NAME("glGetProgramiv");
|
||||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
||||||
|
}
|
||||||
if (programBinarySize) {
|
if (programBinarySize) {
|
||||||
size_t const size = sizeof(Blob) + programBinarySize;
|
size_t const size = sizeof(Blob) + programBinarySize;
|
||||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||||
|
if (UTILS_LIKELY(blob)) {
|
||||||
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glGetProgramBinary");
|
SYSTRACE_NAME("glGetProgramBinary");
|
||||||
glGetProgramBinary(program, programBinarySize, &programBinarySize, &format, blob->data);
|
glGetProgramBinary(program, programBinarySize,
|
||||||
|
&programBinarySize, &format, blob->data);
|
||||||
|
}
|
||||||
GLenum const error = glGetError();
|
GLenum const error = glGetError();
|
||||||
if (error == GL_NO_ERROR) {
|
if (error == GL_NO_ERROR) {
|
||||||
blob->format = format;
|
blob->format = format;
|
||||||
@@ -108,18 +122,4 @@ void OpenGLBlobCache::insert(Platform& platform,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLBlobCache::insert(Platform& platform, BlobCacheKey const& key,
|
|
||||||
GLenum format, void* data, GLsizei programBinarySize) noexcept {
|
|
||||||
SYSTRACE_CALL();
|
|
||||||
if (platform.hasBlobFunc()) {
|
|
||||||
if (programBinarySize) {
|
|
||||||
size_t const size = sizeof(Blob) + programBinarySize;
|
|
||||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
|
||||||
blob->format = format;
|
|
||||||
memcpy(blob->data, data, programBinarySize);
|
|
||||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -25,20 +25,21 @@ namespace filament::backend {
|
|||||||
|
|
||||||
class Platform;
|
class Platform;
|
||||||
class Program;
|
class Program;
|
||||||
|
class OpenGLContext;
|
||||||
|
|
||||||
class OpenGLBlobCache {
|
class OpenGLBlobCache {
|
||||||
public:
|
public:
|
||||||
static GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
explicit OpenGLBlobCache(OpenGLContext& gl) noexcept;
|
||||||
Program const& program) noexcept;
|
|
||||||
|
|
||||||
static void insert(Platform& platform,
|
GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
||||||
|
Program const& program) const noexcept;
|
||||||
|
|
||||||
|
void insert(Platform& platform,
|
||||||
BlobCacheKey const& key, GLuint program) noexcept;
|
BlobCacheKey const& key, GLuint program) noexcept;
|
||||||
|
|
||||||
static void insert(Platform& platform, BlobCacheKey const& key,
|
|
||||||
GLenum format, void* data, GLsizei programBinarySize) noexcept;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Blob;
|
struct Blob;
|
||||||
|
bool mCachingSupported = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -99,38 +99,41 @@ OpenGLContext::OpenGLContext() noexcept {
|
|||||||
|
|
||||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
|
||||||
&gets.max_uniform_block_size);
|
|
||||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
|
||||||
&gets.max_uniform_buffer_bindings);
|
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
|
||||||
&gets.uniform_buffer_offset_alignment);
|
|
||||||
glGetIntegerv(GL_MAX_SAMPLES,
|
|
||||||
&gets.max_samples);
|
|
||||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
|
||||||
&gets.max_draw_buffers);
|
|
||||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
|
||||||
&gets.max_transform_feedback_separate_attribs);
|
|
||||||
#ifdef GL_EXT_texture_filter_anisotropic
|
#ifdef GL_EXT_texture_filter_anisotropic
|
||||||
if (ext.EXT_texture_filter_anisotropic) {
|
if (ext.EXT_texture_filter_anisotropic) {
|
||||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
||||||
|
&gets.max_draw_buffers);
|
||||||
|
glGetIntegerv(GL_MAX_SAMPLES,
|
||||||
|
&gets.max_samples);
|
||||||
|
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||||
|
&gets.max_transform_feedback_separate_attribs);
|
||||||
|
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
||||||
|
&gets.max_uniform_block_size);
|
||||||
|
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||||
|
&gets.max_uniform_buffer_bindings);
|
||||||
|
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS,
|
||||||
|
&gets.num_program_binary_formats);
|
||||||
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
||||||
|
&gets.uniform_buffer_offset_alignment);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||||
else {
|
else {
|
||||||
|
gets.max_anisotropy = 1;
|
||||||
|
gets.max_draw_buffers = 1;
|
||||||
|
gets.max_samples = 1;
|
||||||
|
gets.max_transform_feedback_separate_attribs = 0;
|
||||||
gets.max_uniform_block_size = 0;
|
gets.max_uniform_block_size = 0;
|
||||||
gets.max_uniform_buffer_bindings = 0;
|
gets.max_uniform_buffer_bindings = 0;
|
||||||
|
gets.num_program_binary_formats = 0;
|
||||||
gets.uniform_buffer_offset_alignment = 0;
|
gets.uniform_buffer_offset_alignment = 0;
|
||||||
gets.max_samples = 1;
|
|
||||||
gets.max_draw_buffers = 1;
|
|
||||||
gets.max_transform_feedback_separate_attribs = 0;
|
|
||||||
gets.max_anisotropy = 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
slog.v << "Feature level: " << +mFeatureLevel << '\n';
|
slog.v << "Feature level: " << +mFeatureLevel << '\n';
|
||||||
slog.v << "Active workarounds: " << '\n';
|
slog.v << "Active workarounds: " << '\n';
|
||||||
UTILS_NOUNROLL
|
UTILS_NOUNROLL
|
||||||
@@ -143,13 +146,29 @@ OpenGLContext::OpenGLContext() noexcept {
|
|||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// this is useful for development
|
// this is useful for development
|
||||||
slog.v << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers << '\n'
|
slog.v
|
||||||
<< "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size << '\n'
|
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = "
|
||||||
<< "GL_MAX_SAMPLES = " << gets.max_samples << '\n'
|
<< gets.max_anisotropy << '\n'
|
||||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy << '\n'
|
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
||||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size << '\n'
|
<< gets.max_combined_texture_image_units << '\n'
|
||||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units << '\n'
|
<< "GL_MAX_DRAW_BUFFERS = "
|
||||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment << '\n'
|
<< gets.max_draw_buffers << '\n'
|
||||||
|
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
||||||
|
<< gets.max_renderbuffer_size << '\n'
|
||||||
|
<< "GL_MAX_SAMPLES = "
|
||||||
|
<< gets.max_samples << '\n'
|
||||||
|
<< "GL_MAX_TEXTURE_IMAGE_UNITS = "
|
||||||
|
<< gets.max_texture_image_units << '\n'
|
||||||
|
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
|
||||||
|
<< gets.max_transform_feedback_separate_attribs << '\n'
|
||||||
|
<< "GL_MAX_UNIFORM_BLOCK_SIZE = "
|
||||||
|
<< gets.max_uniform_block_size << '\n'
|
||||||
|
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS = "
|
||||||
|
<< gets.max_uniform_buffer_bindings << '\n'
|
||||||
|
<< "GL_NUM_PROGRAM_BINARY_FORMATS = "
|
||||||
|
<< gets.num_program_binary_formats << '\n'
|
||||||
|
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = "
|
||||||
|
<< gets.uniform_buffer_offset_alignment << '\n'
|
||||||
;
|
;
|
||||||
flush(slog.v);
|
flush(slog.v);
|
||||||
#endif
|
#endif
|
||||||
@@ -265,6 +284,7 @@ void OpenGLContext::setDefaultState() noexcept {
|
|||||||
|
|
||||||
if (ext.EXT_clip_cull_distance) {
|
if (ext.EXT_clip_cull_distance) {
|
||||||
glEnable(GL_CLIP_DISTANCE0);
|
glEnable(GL_CLIP_DISTANCE0);
|
||||||
|
glEnable(GL_CLIP_DISTANCE1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,14 +153,15 @@ public:
|
|||||||
// glGet*() values
|
// glGet*() values
|
||||||
struct Gets {
|
struct Gets {
|
||||||
GLfloat max_anisotropy;
|
GLfloat max_anisotropy;
|
||||||
|
GLint max_combined_texture_image_units;
|
||||||
GLint max_draw_buffers;
|
GLint max_draw_buffers;
|
||||||
GLint max_renderbuffer_size;
|
GLint max_renderbuffer_size;
|
||||||
GLint max_samples;
|
GLint max_samples;
|
||||||
GLint max_uniform_block_size;
|
|
||||||
GLint max_texture_image_units;
|
GLint max_texture_image_units;
|
||||||
GLint max_combined_texture_image_units;
|
|
||||||
GLint max_transform_feedback_separate_attribs;
|
GLint max_transform_feedback_separate_attribs;
|
||||||
|
GLint max_uniform_block_size;
|
||||||
GLint max_uniform_buffer_bindings;
|
GLint max_uniform_buffer_bindings;
|
||||||
|
GLint num_program_binary_formats;
|
||||||
GLint uniform_buffer_offset_alignment;
|
GLint uniform_buffer_offset_alignment;
|
||||||
} gets = {};
|
} gets = {};
|
||||||
|
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||||
Platform::DriverConfig const validConfig {
|
Platform::DriverConfig validConfig {driverConfig};
|
||||||
.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize) };
|
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
||||||
OpenGLDriver* const driver = new OpenGLDriver(ec, validConfig);
|
OpenGLDriver* const driver = new OpenGLDriver(ec, validConfig);
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
@@ -268,9 +268,9 @@ void OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
|||||||
|
|
||||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||||
for (uint32_t i = 0; i < Program::UNIFORM_BINDING_COUNT; i++) {
|
for (uint32_t i = 0; i < Program::UNIFORM_BINDING_COUNT; i++) {
|
||||||
auto [buffer, age] = mUniformBindings[i];
|
auto [id, buffer, age] = mUniformBindings[i];
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
p->updateUniforms(i, buffer, age);
|
p->updateUniforms(i, id, buffer, age);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set the output colorspace for this program (linear or rec709). This in only relevant
|
// Set the output colorspace for this program (linear or rec709). This in only relevant
|
||||||
@@ -479,6 +479,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
|
|||||||
|
|
||||||
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
|
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
|
||||||
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||||
|
bo->gl.id = ++mLastAssignedEmulatedUboId;
|
||||||
bo->gl.buffer = malloc(byteCount);
|
bo->gl.buffer = malloc(byteCount);
|
||||||
memset(bo->gl.buffer, 0, byteCount);
|
memset(bo->gl.buffer, 0, byteCount);
|
||||||
} else {
|
} else {
|
||||||
@@ -555,7 +556,8 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
|||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t size) {
|
void OpenGLDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t size,
|
||||||
|
utils::FixedSizeString<32> debugName) {
|
||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
|
|
||||||
construct<GLSamplerGroup>(sbh, size);
|
construct<GLSamplerGroup>(sbh, size);
|
||||||
@@ -594,8 +596,9 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glTexImage2D(t->gl.target, level, GLint(t->gl.internalFormat),
|
glTexImage2D(t->gl.target, level, GLint(t->gl.internalFormat),
|
||||||
GLsizei(width), GLsizei(height), 0,
|
std::max(GLsizei(1), GLsizei(width >> level)),
|
||||||
format, type, nullptr);
|
std::max(GLsizei(1), GLsizei(height >> level)),
|
||||||
|
0, format, type, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1289,7 +1292,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|||||||
checkDimensions(rt->gl.color[i], color[i].level);
|
checkDimensions(rt->gl.color[i], color[i].level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (UTILS_LIKELY(!getContext().isES2())) {
|
||||||
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
|
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
|
||||||
|
}
|
||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1450,6 +1455,11 @@ void OpenGLDriver::destroySamplerGroup(Handle<HwSamplerGroup> sbh) {
|
|||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
if (sbh) {
|
if (sbh) {
|
||||||
GLSamplerGroup* sb = handle_cast<GLSamplerGroup*>(sbh);
|
GLSamplerGroup* sb = handle_cast<GLSamplerGroup*>(sbh);
|
||||||
|
for (auto& binding : mSamplerBindings) {
|
||||||
|
if (binding == sb) {
|
||||||
|
binding = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
destruct(sbh, sb);
|
destruct(sbh, sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1458,9 +1468,9 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
|||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
|
|
||||||
if (th) {
|
if (th) {
|
||||||
|
auto& gl = mContext;
|
||||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||||
if (UTILS_LIKELY(!t->gl.imported)) {
|
if (UTILS_LIKELY(!t->gl.imported)) {
|
||||||
auto& gl = mContext;
|
|
||||||
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
|
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||||
if (UTILS_UNLIKELY(t->hwStream)) {
|
if (UTILS_UNLIKELY(t->hwStream)) {
|
||||||
@@ -1478,6 +1488,8 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
|||||||
if (t->gl.sidecarRenderBufferMS) {
|
if (t->gl.sidecarRenderBufferMS) {
|
||||||
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
|
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||||
}
|
}
|
||||||
destruct(th, t);
|
destruct(th, t);
|
||||||
}
|
}
|
||||||
@@ -1774,6 +1786,10 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) {
|
|||||||
// support more formats, but it requires querying GL_INTERNALFORMAT_SUPPORTED which is not
|
// support more formats, but it requires querying GL_INTERNALFORMAT_SUPPORTED which is not
|
||||||
// available in OpenGL ES.
|
// available in OpenGL ES.
|
||||||
auto& gl = mContext;
|
auto& gl = mContext;
|
||||||
|
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||||
|
auto [es2format, type] = textureFormatToFormatAndType(format);
|
||||||
|
return es2format != GL_NONE && type != GL_NONE;
|
||||||
|
}
|
||||||
switch (format) {
|
switch (format) {
|
||||||
// Core formats.
|
// Core formats.
|
||||||
case TextureFormat::R8:
|
case TextureFormat::R8:
|
||||||
@@ -1953,6 +1969,13 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
|
|||||||
GLSwapChain* scRead = handle_cast<GLSwapChain*>(schRead);
|
GLSwapChain* scRead = handle_cast<GLSwapChain*>(schRead);
|
||||||
mPlatform.makeCurrent(scDraw->swapChain, scRead->swapChain);
|
mPlatform.makeCurrent(scDraw->swapChain, scRead->swapChain);
|
||||||
mCurrentDrawSwapChain = scDraw;
|
mCurrentDrawSwapChain = scDraw;
|
||||||
|
|
||||||
|
// From the GL spec for glViewport and glScissor:
|
||||||
|
// When a GL context is first attached to a window, width and height are set to the
|
||||||
|
// dimensions of that window.
|
||||||
|
// So basically, our viewport/scissor can be reset to "something" here.
|
||||||
|
mContext.state.window.viewport = {};
|
||||||
|
mContext.state.window.scissor = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -2268,8 +2291,16 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum const glFormat = getFormat(p.format);
|
GLenum glFormat;
|
||||||
GLenum const glType = getType(p.type);
|
GLenum glType;
|
||||||
|
if (mContext.isES2()) {
|
||||||
|
auto formatAndType = textureFormatToFormatAndType(t->format);
|
||||||
|
glFormat = formatAndType.first;
|
||||||
|
glType = formatAndType.second;
|
||||||
|
} else {
|
||||||
|
glFormat = getFormat(p.format);
|
||||||
|
glType = getType(p.type);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||||
if (!gl.isES2()) {
|
if (!gl.isES2()) {
|
||||||
@@ -2879,7 +2910,11 @@ void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t ind
|
|||||||
assert_invariant(offset + size <= ub->byteCount);
|
assert_invariant(offset + size <= ub->byteCount);
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(ub->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
if (UTILS_UNLIKELY(ub->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||||
mUniformBindings[index] = { static_cast<uint8_t const*>(ub->gl.buffer) + offset, ub->age };
|
mUniformBindings[index] = {
|
||||||
|
ub->gl.id,
|
||||||
|
static_cast<uint8_t const*>(ub->gl.buffer) + offset,
|
||||||
|
ub->age,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
GLenum const target = GLUtils::getBufferBindingType(bindingType);
|
GLenum const target = GLUtils::getBufferBindingType(bindingType);
|
||||||
|
|
||||||
|
|||||||
@@ -82,12 +82,10 @@ public:
|
|||||||
: HwBufferObject(size), usage(usage), bindingType(bindingType) {
|
: HwBufferObject(size), usage(usage), bindingType(bindingType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
struct {
|
struct {
|
||||||
GLuint id;
|
GLuint id;
|
||||||
|
union {
|
||||||
GLenum binding;
|
GLenum binding;
|
||||||
};
|
|
||||||
void* buffer;
|
void* buffer;
|
||||||
};
|
};
|
||||||
} gl;
|
} gl;
|
||||||
@@ -363,7 +361,8 @@ private:
|
|||||||
void setScissor(Viewport const& scissor) noexcept;
|
void setScissor(Viewport const& scissor) noexcept;
|
||||||
|
|
||||||
// ES2 only. Uniform buffer emulation binding points
|
// ES2 only. Uniform buffer emulation binding points
|
||||||
std::array<std::pair<void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
GLuint mLastAssignedEmulatedUboId = 0;
|
||||||
|
std::array<std::tuple<GLuint, void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
||||||
|
|
||||||
// sampler buffer binding points (nullptr if not used)
|
// sampler buffer binding points (nullptr if not used)
|
||||||
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
|
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
|
||||||
|
|||||||
@@ -208,9 +208,11 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
|||||||
auto const& UTILS_RESTRICT usedBindingPoints = mUsedSamplerBindingPoints;
|
auto const& UTILS_RESTRICT usedBindingPoints = mUsedSamplerBindingPoints;
|
||||||
|
|
||||||
for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
|
for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
|
||||||
auto const binding = usedBindingPoints[i];
|
size_t const binding = usedBindingPoints[i];
|
||||||
|
assert_invariant(binding < Program::SAMPLER_BINDING_COUNT);
|
||||||
auto const * const sb = samplerBindings[binding];
|
auto const * const sb = samplerBindings[binding];
|
||||||
assert_invariant(sb);
|
assert_invariant(sb);
|
||||||
|
if (!sb) continue; // should never happen, this would be a user error.
|
||||||
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
|
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
|
||||||
const GLTexture* const t = sb->textureUnitEntries[j].texture;
|
const GLTexture* const t = sb->textureUnitEntries[j].texture;
|
||||||
if (t) { // program may not use all samplers of sampler group
|
if (t) { // program may not use all samplers of sampler group
|
||||||
@@ -227,15 +229,16 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
|||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLProgram::updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept {
|
void OpenGLProgram::updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept {
|
||||||
assert_invariant(mUniformsRecords);
|
assert_invariant(mUniformsRecords);
|
||||||
assert_invariant(buffer);
|
assert_invariant(buffer);
|
||||||
|
|
||||||
// only update the uniforms if the UBO has changed since last time we updated
|
// only update the uniforms if the UBO has changed since last time we updated
|
||||||
UniformsRecord const& records = mUniformsRecords[index];
|
UniformsRecord const& records = mUniformsRecords[index];
|
||||||
if (records.age == age) {
|
if (records.id == id && records.age == age) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
records.id = id;
|
||||||
records.age = age;
|
records.age = age;
|
||||||
|
|
||||||
assert_invariant(records.uniforms.size() == records.locations.size());
|
assert_invariant(records.uniforms.size() == records.locations.size());
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
} gl; // 12 bytes
|
} gl; // 12 bytes
|
||||||
|
|
||||||
// For ES2 only
|
// For ES2 only
|
||||||
void updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept;
|
void updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept;
|
||||||
void setRec709ColorSpace(bool rec709) const noexcept;
|
void setRec709ColorSpace(bool rec709) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -98,6 +98,7 @@ private:
|
|||||||
struct UniformsRecord {
|
struct UniformsRecord {
|
||||||
Program::UniformInfo uniforms;
|
Program::UniformInfo uniforms;
|
||||||
LocationInfo locations;
|
LocationInfo locations;
|
||||||
|
mutable GLuint id = 0;
|
||||||
mutable uint16_t age = std::numeric_limits<uint16_t>::max();
|
mutable uint16_t age = std::numeric_limits<uint16_t>::max();
|
||||||
};
|
};
|
||||||
UniformsRecord const* mUniformsRecords = nullptr;
|
UniformsRecord const* mUniformsRecords = nullptr;
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ 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 {
|
||||||
@@ -135,6 +140,7 @@ void* ShaderCompilerService::getUserData(const program_token_t& token) noexcept
|
|||||||
|
|
||||||
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
|
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
|
||||||
: mDriver(driver),
|
: mDriver(driver),
|
||||||
|
mBlobCache(driver.getContext()),
|
||||||
mCallbackManager(driver),
|
mCallbackManager(driver),
|
||||||
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
|
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
|
||||||
}
|
}
|
||||||
@@ -214,7 +220,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
|||||||
token->attributes = std::move(program.getAttributes());
|
token->attributes = std::move(program.getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
token->gl.program = OpenGLBlobCache::retrieve(&token->key, mDriver.mPlatform, program);
|
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
|
||||||
if (token->gl.program) {
|
if (token->gl.program) {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -244,7 +250,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
|||||||
// We need to query the link status here to guarantee that the
|
// We need to query the link status here to guarantee that the
|
||||||
// program is compiled and linked now (we don't want this to be
|
// program is compiled and linked now (we don't want this to be
|
||||||
// deferred to later). We don't care about the result at this point.
|
// deferred to later). We don't care about the result at this point.
|
||||||
GLint status;
|
GLint status = GL_FALSE;
|
||||||
glGetProgramiv(glProgram, GL_LINK_STATUS, &status);
|
glGetProgramiv(glProgram, GL_LINK_STATUS, &status);
|
||||||
programData.program = glProgram;
|
programData.program = glProgram;
|
||||||
|
|
||||||
@@ -257,9 +263,9 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
|||||||
mCallbackManager.put(token->handle);
|
mCallbackManager.put(token->handle);
|
||||||
|
|
||||||
// caching must be the last thing we do
|
// caching must be the last thing we do
|
||||||
if (token->key) {
|
if (token->key && status == GL_TRUE) {
|
||||||
// Attempt to cache. This calls glGetProgramBinary.
|
// Attempt to cache. This calls glGetProgramBinary.
|
||||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, glProgram);
|
mBlobCache.insert(mDriver.mPlatform, token->key, glProgram);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -312,7 +318,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
|||||||
// do this later, maybe depending on CPU usage?
|
// do this later, maybe depending on CPU usage?
|
||||||
// attempt to cache if we don't have a thread pool (otherwise it's done
|
// attempt to cache if we don't have a thread pool (otherwise it's done
|
||||||
// by the pool).
|
// by the pool).
|
||||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -336,7 +342,23 @@ GLuint ShaderCompilerService::getProgram(ShaderCompilerService::program_token_t&
|
|||||||
|
|
||||||
token->canceled = true;
|
token->canceled = true;
|
||||||
|
|
||||||
token->compiler.cancelTickOp(token);
|
bool canceled = 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) {
|
||||||
@@ -410,7 +432,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
|
|||||||
mCallbackManager.put(token->handle);
|
mCallbackManager.put(token->handle);
|
||||||
|
|
||||||
if (token->key) {
|
if (token->key) {
|
||||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if we don't have a program yet, block until we get it.
|
// if we don't have a program yet, block until we get it.
|
||||||
@@ -662,7 +684,7 @@ void ShaderCompilerService::runAtNextTick(CompilerPriorityQueue priority,
|
|||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCompilerService::cancelTickOp(program_token_t token) noexcept {
|
bool 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) {
|
||||||
@@ -670,9 +692,11 @@ void 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 {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "CallbackManager.h"
|
#include "CallbackManager.h"
|
||||||
#include "CompilerThreadPool.h"
|
#include "CompilerThreadPool.h"
|
||||||
|
#include "OpenGLBlobCache.h"
|
||||||
|
|
||||||
#include <backend/CallbackHandler.h>
|
#include <backend/CallbackHandler.h>
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
@@ -95,6 +96,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
OpenGLDriver& mDriver;
|
OpenGLDriver& mDriver;
|
||||||
|
OpenGLBlobCache mBlobCache;
|
||||||
CallbackManager mCallbackManager;
|
CallbackManager mCallbackManager;
|
||||||
CompilerThreadPool mCompilerThreadPool;
|
CompilerThreadPool mCompilerThreadPool;
|
||||||
|
|
||||||
@@ -141,7 +143,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;
|
||||||
void cancelTickOp(program_token_t token) noexcept;
|
bool 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>;
|
||||||
|
|||||||
@@ -190,8 +190,10 @@ using namespace glext;
|
|||||||
|
|
||||||
#if defined(GL_EXT_clip_cull_distance)
|
#if defined(GL_EXT_clip_cull_distance)
|
||||||
# define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT
|
# define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT
|
||||||
|
# define GL_CLIP_DISTANCE1 GL_CLIP_DISTANCE1_EXT
|
||||||
#else
|
#else
|
||||||
# define GL_CLIP_DISTANCE0 0x3000
|
# define GL_CLIP_DISTANCE0 0x3000
|
||||||
|
# define GL_CLIP_DISTANCE1 0x3001
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GL_KHR_debug)
|
#if defined(GL_KHR_debug)
|
||||||
|
|||||||
@@ -97,13 +97,32 @@ int PlatformEGL::getOSVersion() const noexcept {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlatformEGL::isOpenGL() const noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept {
|
Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
||||||
|
|
||||||
EGLint major, minor;
|
EGLint major, minor;
|
||||||
EGLBoolean const initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
EGLDeviceEXT eglDevice;
|
||||||
|
EGLint numDevices;
|
||||||
|
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
|
||||||
|
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
|
||||||
|
if (eglQueryDevicesEXT != nullptr) {
|
||||||
|
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
|
||||||
|
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
|
||||||
|
eglGetProcAddress("eglGetPlatformDisplay"))) {
|
||||||
|
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0);
|
||||||
|
initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(!initialized)) {
|
if (UTILS_UNLIKELY(!initialized)) {
|
||||||
slog.e << "eglInitialize failed" << io::endl;
|
slog.e << "eglInitialize failed" << io::endl;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -148,10 +167,16 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
|
|||||||
constexpr bool requestES2Context = false;
|
constexpr bool requestES2Context = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Config contextAttribs;
|
||||||
|
|
||||||
|
if (isOpenGL()) {
|
||||||
|
// Request a OpenGL 4.1 context
|
||||||
|
contextAttribs[EGL_CONTEXT_MAJOR_VERSION] = 4;
|
||||||
|
contextAttribs[EGL_CONTEXT_MINOR_VERSION] = 1;
|
||||||
|
} else {
|
||||||
// Request a ES2 context, devices that support ES3 will return an ES3 context
|
// Request a ES2 context, devices that support ES3 will return an ES3 context
|
||||||
Config contextAttribs = {
|
contextAttribs[EGL_CONTEXT_CLIENT_VERSION] = 2;
|
||||||
{ EGL_CONTEXT_CLIENT_VERSION, 2 },
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// FOR TESTING ONLY, enforce the ES version we're asking for.
|
// FOR TESTING ONLY, enforce the ES version we're asking for.
|
||||||
// FIXME: we should check EGL_ANGLE_create_context_backwards_compatible, however, at least
|
// FIXME: we should check EGL_ANGLE_create_context_backwards_compatible, however, at least
|
||||||
@@ -172,14 +197,17 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
|
|||||||
// config use for creating the context
|
// config use for creating the context
|
||||||
EGLConfig eglConfig = EGL_NO_CONFIG_KHR;
|
EGLConfig eglConfig = EGL_NO_CONFIG_KHR;
|
||||||
|
|
||||||
|
|
||||||
|
if (UTILS_UNLIKELY(!ext.egl.KHR_no_config_context)) {
|
||||||
// find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use
|
// find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use
|
||||||
// for the dummy pbuffer surface.
|
// for the dummy pbuffer surface.
|
||||||
mEGLConfig = findSwapChainConfig(0);
|
mEGLConfig = findSwapChainConfig(
|
||||||
|
SWAP_CHAIN_CONFIG_TRANSPARENT |
|
||||||
|
SWAP_CHAIN_HAS_STENCIL_BUFFER,
|
||||||
|
true, true);
|
||||||
if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) {
|
if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) {
|
||||||
goto error; // error already logged
|
goto error; // error already logged
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(!ext.egl.KHR_no_config_context)) {
|
|
||||||
// if we don't have the EGL_KHR_no_config_context the context must be created with
|
// if we don't have the EGL_KHR_no_config_context the context must be created with
|
||||||
// the same config as the swapchain, so we have no choice but to create a
|
// the same config as the swapchain, so we have no choice but to create a
|
||||||
// transparent config.
|
// transparent config.
|
||||||
@@ -333,22 +361,36 @@ void PlatformEGL::terminate() noexcept {
|
|||||||
eglReleaseThread();
|
eglReleaseThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags) const {
|
EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const {
|
||||||
// Find config that support ES3.
|
// Find config that support ES3.
|
||||||
EGLConfig config = EGL_NO_CONFIG_KHR;
|
EGLConfig config = EGL_NO_CONFIG_KHR;
|
||||||
EGLint configsCount;
|
EGLint configsCount;
|
||||||
Config configAttribs = {
|
Config configAttribs = {
|
||||||
{ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT },
|
|
||||||
{ EGL_RED_SIZE, 8 },
|
{ EGL_RED_SIZE, 8 },
|
||||||
{ EGL_GREEN_SIZE, 8 },
|
{ EGL_GREEN_SIZE, 8 },
|
||||||
{ EGL_BLUE_SIZE, 8 },
|
{ EGL_BLUE_SIZE, 8 },
|
||||||
{ EGL_ALPHA_SIZE, (flags & SWAP_CHAIN_CONFIG_TRANSPARENT) ? 8 : 0 },
|
{ EGL_ALPHA_SIZE, (flags & SWAP_CHAIN_CONFIG_TRANSPARENT) ? 8 : 0 },
|
||||||
{ EGL_DEPTH_SIZE, 24 },
|
{ EGL_DEPTH_SIZE, 24 },
|
||||||
|
{ EGL_STENCIL_SIZE, (flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) ? 8 : 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!ext.egl.KHR_no_config_context) {
|
||||||
|
if (isOpenGL()) {
|
||||||
|
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT;
|
||||||
|
} else {
|
||||||
|
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT;
|
||||||
if (ext.egl.KHR_create_context) {
|
if (ext.egl.KHR_create_context) {
|
||||||
configAttribs[EGL_RECORDABLE_ANDROID] |= EGL_OPENGL_ES3_BIT_KHR;
|
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window) {
|
||||||
|
configAttribs[EGL_SURFACE_TYPE] |= EGL_WINDOW_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pbuffer) {
|
||||||
|
configAttribs[EGL_SURFACE_TYPE] |= EGL_PBUFFER_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.egl.ANDROID_recordable) {
|
if (ext.egl.ANDROID_recordable) {
|
||||||
@@ -391,7 +433,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
|
|||||||
|
|
||||||
EGLConfig config = EGL_NO_CONFIG_KHR;
|
EGLConfig config = EGL_NO_CONFIG_KHR;
|
||||||
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
|
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
|
||||||
config = findSwapChainConfig(flags);
|
config = findSwapChainConfig(flags, true, false);
|
||||||
} else {
|
} else {
|
||||||
config = mEGLConfig;
|
config = mEGLConfig;
|
||||||
}
|
}
|
||||||
@@ -427,7 +469,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
|
|||||||
|
|
||||||
EGLConfig config = EGL_NO_CONFIG_KHR;
|
EGLConfig config = EGL_NO_CONFIG_KHR;
|
||||||
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
|
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
|
||||||
config = findSwapChainConfig(flags);
|
config = findSwapChainConfig(flags, false, true);
|
||||||
} else {
|
} else {
|
||||||
config = mEGLConfig;
|
config = mEGLConfig;
|
||||||
}
|
}
|
||||||
@@ -569,7 +611,7 @@ EGLint& PlatformEGL::Config::operator[](EGLint name) {
|
|||||||
auto pos = std::find_if(mConfig.begin(), mConfig.end(),
|
auto pos = std::find_if(mConfig.begin(), mConfig.end(),
|
||||||
[name](auto&& v) { return v.first == name; });
|
[name](auto&& v) { return v.first == name; });
|
||||||
if (pos == mConfig.end()) {
|
if (pos == mConfig.end()) {
|
||||||
mConfig.insert(pos - 1, { name, EGL_NONE });
|
mConfig.insert(pos - 1, { name, 0 });
|
||||||
pos = mConfig.end() - 2;
|
pos = mConfig.end() - 2;
|
||||||
}
|
}
|
||||||
return pos->second;
|
return pos->second;
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
|
|||||||
AcquiredImage acquiredImage;
|
AcquiredImage acquiredImage;
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
};
|
};
|
||||||
Closure* closure = new Closure(source, mEGLDisplay);
|
Closure* closure = new(std::nothrow) Closure(source, mEGLDisplay);
|
||||||
auto patchedCallback = [](void* image, void* userdata) {
|
auto patchedCallback = [](void* image, void* userdata) {
|
||||||
Closure* closure = (Closure*)userdata;
|
Closure* closure = (Closure*)userdata;
|
||||||
if (eglDestroyImageKHR(closure->display, (EGLImageKHR) image) == EGL_FALSE) {
|
if (eglDestroyImageKHR(closure->display, (EGLImageKHR) image) == EGL_FALSE) {
|
||||||
|
|||||||
@@ -30,21 +30,14 @@ using namespace utils;
|
|||||||
namespace filament {
|
namespace filament {
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
namespace glext {
|
|
||||||
UTILS_PRIVATE PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = {};
|
|
||||||
UTILS_PRIVATE PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = {};
|
|
||||||
UTILS_PRIVATE PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = {};
|
|
||||||
UTILS_PRIVATE PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = {};
|
|
||||||
UTILS_PRIVATE PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = {};
|
|
||||||
}
|
|
||||||
using namespace glext;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PlatformEGLHeadless::PlatformEGLHeadless() noexcept
|
PlatformEGLHeadless::PlatformEGLHeadless() noexcept
|
||||||
: PlatformEGL() {
|
: PlatformEGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlatformEGLHeadless::isOpenGL() const noexcept {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
|
backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
|
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
|
||||||
@@ -58,166 +51,7 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from the base class and modified slightly. Should be cleaned up/improved later.
|
return PlatformEGL::createDriver(sharedContext, driverConfig);
|
||||||
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
||||||
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
|
||||||
|
|
||||||
EGLint major, minor;
|
|
||||||
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
EGLDeviceEXT eglDevice;
|
|
||||||
EGLint numDevices;
|
|
||||||
|
|
||||||
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
|
|
||||||
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
|
|
||||||
if (eglQueryDevicesEXT != NULL) {
|
|
||||||
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
|
|
||||||
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
|
|
||||||
eglGetProcAddress("eglGetPlatformDisplay"))) {
|
|
||||||
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0);
|
|
||||||
initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(!initialized)) {
|
|
||||||
slog.e << "eglInitialize failed" << io::endl;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto extensions = GLUtils::split(eglQueryString(mEGLDisplay, EGL_EXTENSIONS));
|
|
||||||
|
|
||||||
eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
|
|
||||||
eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
|
|
||||||
eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
|
|
||||||
|
|
||||||
eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
|
|
||||||
eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
|
|
||||||
|
|
||||||
EGLint configsCount;
|
|
||||||
|
|
||||||
EGLint configAttribs[] = {
|
|
||||||
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_ALPHA_SIZE, 0,
|
|
||||||
EGL_DEPTH_SIZE, 32,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
EGLint contextAttribs[] = {
|
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
|
||||||
EGL_NONE, EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
EGLint pbufferAttribs[] = {
|
|
||||||
EGL_WIDTH, 1,
|
|
||||||
EGL_HEIGHT, 1,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
// When we don't have a shared context and we're in release mode, we always activate the
|
|
||||||
// EGL_KHR_create_context_no_error extension.
|
|
||||||
if (!sharedContext && extensions.has("EGL_KHR_create_context_no_error")) {
|
|
||||||
contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
|
|
||||||
contextAttribs[3] = EGL_TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EGLConfig eglConfig = nullptr;
|
|
||||||
|
|
||||||
// find an opaque config
|
|
||||||
if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) {
|
|
||||||
logEglError("eglChooseConfig");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to a 24-bit depth buffer
|
|
||||||
if (configsCount == 0) {
|
|
||||||
configAttribs[10] = EGL_DEPTH_SIZE;
|
|
||||||
configAttribs[11] = 24;
|
|
||||||
|
|
||||||
if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) {
|
|
||||||
logEglError("eglChooseConfig");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find a transparent config
|
|
||||||
configAttribs[8] = EGL_ALPHA_SIZE;
|
|
||||||
configAttribs[9] = 8;
|
|
||||||
if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLTransparentConfig, 1, &configsCount) ||
|
|
||||||
(configAttribs[13] == EGL_DONT_CARE && configsCount == 0)) {
|
|
||||||
logEglError("eglChooseConfig");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extensions.has("EGL_KHR_no_config_context")) {
|
|
||||||
// if we have the EGL_KHR_no_config_context, we don't need to worry about the config
|
|
||||||
// when creating the context, otherwise, we must always pick a transparent config.
|
|
||||||
eglConfig = mEGLConfig = mEGLTransparentConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the pbuffer dummy surface is always created with a transparent surface because
|
|
||||||
// either we have EGL_KHR_no_config_context and it doesn't matter, or we don't and
|
|
||||||
// we must use a transparent surface
|
|
||||||
mEGLDummySurface = eglCreatePbufferSurface(mEGLDisplay, mEGLTransparentConfig, pbufferAttribs);
|
|
||||||
if (mEGLDummySurface == EGL_NO_SURFACE) {
|
|
||||||
logEglError("eglCreatePbufferSurface");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs);
|
|
||||||
if (mEGLContext == EGL_NO_CONTEXT && sharedContext &&
|
|
||||||
extensions.has("EGL_KHR_create_context_no_error")) {
|
|
||||||
// context creation could fail because of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
|
|
||||||
// not matching the sharedContext. Try with it.
|
|
||||||
contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
|
|
||||||
contextAttribs[3] = EGL_TRUE;
|
|
||||||
mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs);
|
|
||||||
}
|
|
||||||
if (UTILS_UNLIKELY(mEGLContext == EGL_NO_CONTEXT)) {
|
|
||||||
// eglCreateContext failed
|
|
||||||
logEglError("eglCreateContext");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!makeCurrent(mEGLDummySurface, mEGLDummySurface)) {
|
|
||||||
// eglMakeCurrent failed
|
|
||||||
logEglError("eglMakeCurrent");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeGlExtensions();
|
|
||||||
|
|
||||||
clearGlError();
|
|
||||||
|
|
||||||
// success!!
|
|
||||||
return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig);
|
|
||||||
|
|
||||||
error:
|
|
||||||
// if we're here, we've failed
|
|
||||||
if (mEGLDummySurface) {
|
|
||||||
eglDestroySurface(mEGLDisplay, mEGLDummySurface);
|
|
||||||
}
|
|
||||||
if (mEGLContext) {
|
|
||||||
eglDestroyContext(mEGLDisplay, mEGLContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
mEGLDummySurface = EGL_NO_SURFACE;
|
|
||||||
mEGLContext = EGL_NO_CONTEXT;
|
|
||||||
|
|
||||||
eglTerminate(mEGLDisplay);
|
|
||||||
eglReleaseThread();
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PlatformWGL::isExtraContextSupported() const noexcept {
|
bool PlatformWGL::isExtraContextSupported() const noexcept {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformWGL::createContext(bool shared) {
|
void PlatformWGL::createContext(bool shared) {
|
||||||
|
|||||||
@@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
#include "generated/vkshaders/vkshaders.h"
|
#include "generated/vkshaders/vkshaders.h"
|
||||||
|
|
||||||
#define FILAMENT_VULKAN_CHECK_BLIT_FORMAT 0
|
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
using namespace utils;
|
using namespace utils;
|
||||||
|
|
||||||
@@ -42,16 +40,20 @@ namespace {
|
|||||||
inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect, VkFilter filter,
|
inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect, VkFilter filter,
|
||||||
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
|
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
|
||||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
||||||
const VkImageBlit blitRegions[1] = {{.srcSubresource = {aspect, src.level, src.layer, 1},
|
const VkImageBlit blitRegions[1] = {{
|
||||||
|
.srcSubresource = {aspect, src.level, src.layer, 1},
|
||||||
.srcOffsets = {srcRect[0], srcRect[1]},
|
.srcOffsets = {srcRect[0], srcRect[1]},
|
||||||
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
||||||
.dstOffsets = {dstRect[0], dstRect[1]}}};
|
.dstOffsets = {dstRect[0], dstRect[1]},
|
||||||
|
}};
|
||||||
|
|
||||||
const VkImageResolve resolveRegions[1] = {{.srcSubresource = {aspect, src.level, src.layer, 1},
|
const VkImageResolve resolveRegions[1] = {{
|
||||||
|
.srcSubresource = {aspect, src.level, src.layer, 1},
|
||||||
.srcOffset = srcRect[0],
|
.srcOffset = srcRect[0],
|
||||||
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
||||||
.dstOffset = dstRect[0],
|
.dstOffset = dstRect[0],
|
||||||
.extent = {srcExtent.width, srcExtent.height, 1}}};
|
.extent = {srcExtent.width, srcExtent.height, 1},
|
||||||
|
}};
|
||||||
|
|
||||||
const VkImageSubresourceRange srcRange = {
|
const VkImageSubresourceRange srcRange = {
|
||||||
.aspectMask = aspect,
|
.aspectMask = aspect,
|
||||||
@@ -69,13 +71,16 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
|||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||||
<< "layout=" << src.getLayout()
|
<< " layout=" << src.getLayout()
|
||||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||||
<< "layout=" << dst.getLayout() << utils::io::endl;
|
<< " layout=" << dst.getLayout() << utils::io::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanLayout oldSrcLayout = src.getLayout();
|
||||||
|
VulkanLayout oldDstLayout = dst.getLayout();
|
||||||
|
|
||||||
src.texture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
|
src.texture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
|
||||||
dst.texture->transitionLayout(cmdbuffer, dstRange, VulkanLayout::TRANSFER_DST);
|
dst.texture->transitionLayout(cmdbuffer, dstRange, VulkanLayout::TRANSFER_DST);
|
||||||
|
|
||||||
@@ -93,17 +98,14 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
|||||||
1, blitRegions, filter);
|
1, blitRegions, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanLayout newSrcLayout = ImgUtil::getDefaultLayout(src.texture->usage);
|
if (oldSrcLayout == VulkanLayout::UNDEFINED) {
|
||||||
VulkanLayout const newDstLayout = ImgUtil::getDefaultLayout(dst.texture->usage);
|
oldSrcLayout = ImgUtil::getDefaultLayout(src.texture->usage);
|
||||||
|
|
||||||
// In the case of blitting the depth attachment, we transition the source into GENERAL (for
|
|
||||||
// sampling) and set the copy as ATTACHMENT_OPTIMAL (to be set as the attachment).
|
|
||||||
if (any(src.texture->usage & TextureUsage::DEPTH_ATTACHMENT)) {
|
|
||||||
newSrcLayout = VulkanLayout::DEPTH_SAMPLER;
|
|
||||||
}
|
}
|
||||||
|
if (oldDstLayout == VulkanLayout::UNDEFINED) {
|
||||||
src.texture->transitionLayout(cmdbuffer, srcRange, newSrcLayout);
|
oldDstLayout = ImgUtil::getDefaultLayout(dst.texture->usage);
|
||||||
dst.texture->transitionLayout(cmdbuffer, dstRange, newDstLayout);
|
}
|
||||||
|
src.texture->transitionLayout(cmdbuffer, srcRange, oldSrcLayout);
|
||||||
|
dst.texture->transitionLayout(cmdbuffer, dstRange, oldDstLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlitterUniforms {
|
struct BlitterUniforms {
|
||||||
@@ -132,7 +134,7 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
|||||||
const VulkanAttachment dst = args.dstTarget->getColor(0);
|
const VulkanAttachment dst = args.dstTarget->getColor(0);
|
||||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
|
||||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
|
||||||
VkPhysicalDevice const gpu = mPhysicalDevice;
|
VkPhysicalDevice const gpu = mPhysicalDevice;
|
||||||
VkFormatProperties info;
|
VkFormatProperties info;
|
||||||
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
||||||
@@ -147,7 +149,7 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
VkCommandBuffer const cmdbuffer = commands.buffer();
|
||||||
commands.acquire(src.texture);
|
commands.acquire(src.texture);
|
||||||
commands.acquire(dst.texture);
|
commands.acquire(dst.texture);
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
|||||||
const VulkanAttachment dst = args.dstTarget->getDepth();
|
const VulkanAttachment dst = args.dstTarget->getDepth();
|
||||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
|
||||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
|
||||||
VkPhysicalDevice const gpu = mPhysicalDevice;
|
VkPhysicalDevice const gpu = mPhysicalDevice;
|
||||||
VkFormatProperties info;
|
VkFormatProperties info;
|
||||||
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
||||||
@@ -184,7 +186,7 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
VkCommandBuffer const cmdbuffer = commands.buffer();
|
||||||
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,
|
||||||
@@ -192,22 +194,20 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanBlitter::terminate() noexcept {
|
void VulkanBlitter::terminate() noexcept {
|
||||||
if (mDevice) {
|
if (mDepthResolveProgram) {
|
||||||
delete mDepthResolveProgram;
|
delete mDepthResolveProgram;
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we created these shader modules in the constructor, the device might not be ready yet.
|
// If we created these shader modules in the constructor, the device might not be ready yet.
|
||||||
@@ -237,17 +237,18 @@ void VulkanBlitter::lazyInit() noexcept {
|
|||||||
|
|
||||||
VkShaderModule vertexShader = decode(VKSHADERS_BLITDEPTHVS_DATA, VKSHADERS_BLITDEPTHVS_SIZE);
|
VkShaderModule vertexShader = decode(VKSHADERS_BLITDEPTHVS_DATA, VKSHADERS_BLITDEPTHVS_SIZE);
|
||||||
VkShaderModule fragmentShader = decode(VKSHADERS_BLITDEPTHFS_DATA, VKSHADERS_BLITDEPTHFS_SIZE);
|
VkShaderModule fragmentShader = decode(VKSHADERS_BLITDEPTHFS_DATA, VKSHADERS_BLITDEPTHFS_SIZE);
|
||||||
mDepthResolveProgram = new VulkanProgram(mDevice, vertexShader, fragmentShader);
|
|
||||||
|
|
||||||
// Allocate one anonymous sampler at slot 0.
|
// Allocate one anonymous sampler at slot 0.
|
||||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.reserve(1);
|
VulkanProgram::CustomSamplerInfoList samplers = {
|
||||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.resize(1);
|
{0, 0, ShaderStageFlags::FRAGMENT},
|
||||||
|
};
|
||||||
|
mDepthResolveProgram = new VulkanProgram(mDevice, vertexShader, fragmentShader, samplers);
|
||||||
|
|
||||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
#if FVK_ENABLED(FVK_DEBUG_BLITTER)
|
||||||
utils::slog.d << "Created Shader Module for VulkanBlitter "
|
utils::slog.d << "Created Shader Module for VulkanBlitter "
|
||||||
<< "shaders = (" << vertexShader << ", " << fragmentShader << ")"
|
<< "shaders = (" << vertexShader << ", " << fragmentShader << ")"
|
||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
}
|
#endif
|
||||||
|
|
||||||
static const float kTriangleVertices[] = {
|
static const float kTriangleVertices[] = {
|
||||||
-1.0f, -1.0f,
|
-1.0f, -1.0f,
|
||||||
@@ -257,7 +258,7 @@ void VulkanBlitter::lazyInit() noexcept {
|
|||||||
};
|
};
|
||||||
|
|
||||||
VulkanCommandBuffer& commands = mCommands->get();
|
VulkanCommandBuffer& commands = mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands.cmdbuffer;
|
VkCommandBuffer const cmdbuffer = commands.buffer();
|
||||||
|
|
||||||
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));
|
||||||
@@ -278,7 +279,7 @@ void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, V
|
|||||||
lazyInit();
|
lazyInit();
|
||||||
|
|
||||||
VulkanCommandBuffer* commands = &mCommands->get();
|
VulkanCommandBuffer* commands = &mCommands->get();
|
||||||
VkCommandBuffer const cmdbuffer = commands->cmdbuffer;
|
VkCommandBuffer const cmdbuffer = commands->buffer();
|
||||||
commands->acquire(src.texture);
|
commands->acquire(src.texture);
|
||||||
commands->acquire(dst.texture);
|
commands->acquire(dst.texture);
|
||||||
|
|
||||||
@@ -359,7 +360,7 @@ void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, V
|
|||||||
// DRAW THE TRIANGLE
|
// DRAW THE TRIANGLE
|
||||||
// -----------------
|
// -----------------
|
||||||
|
|
||||||
mPipelineCache.bindProgram(*mDepthResolveProgram);
|
mPipelineCache.bindProgram(mDepthResolveProgram);
|
||||||
mPipelineCache.bindPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
mPipelineCache.bindPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||||
|
|
||||||
auto vkraster = mPipelineCache.getCurrentRasterState();
|
auto vkraster = mPipelineCache.getCurrentRasterState();
|
||||||
@@ -381,13 +382,19 @@ void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, V
|
|||||||
vkraster.colorTargetCount = 0;
|
vkraster.colorTargetCount = 0;
|
||||||
mPipelineCache.bindRasterState(vkraster);
|
mPipelineCache.bindRasterState(vkraster);
|
||||||
|
|
||||||
VulkanPipelineCache::VertexArray varray = {};
|
|
||||||
VkBuffer buffers[1] = {};
|
VkBuffer buffers[1] = {};
|
||||||
VkDeviceSize offsets[1] = {};
|
VkDeviceSize offsets[1] = {};
|
||||||
buffers[0] = mTriangleBuffer->getGpuBuffer();
|
buffers[0] = mTriangleBuffer->getGpuBuffer();
|
||||||
varray.attributes[0] = { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT };
|
VkVertexInputAttributeDescription attribDesc = {
|
||||||
varray.buffers[0] = { .binding = 0, .stride = sizeof(float) * 2 };
|
.location = 0,
|
||||||
mPipelineCache.bindVertexArray(varray);
|
.binding = 0,
|
||||||
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||||
|
};
|
||||||
|
VkVertexInputBindingDescription bufferDesc = {
|
||||||
|
.binding = 0,
|
||||||
|
.stride = sizeof(float) * 2,
|
||||||
|
};
|
||||||
|
mPipelineCache.bindVertexArray(&attribDesc, &bufferDesc, 1);
|
||||||
|
|
||||||
// Select nearest filtering and clamp_to_edge.
|
// Select nearest filtering and clamp_to_edge.
|
||||||
VkSampler vksampler = mSamplerCache.getSampler({});
|
VkSampler vksampler = mSamplerCache.getSampler({});
|
||||||
|
|||||||
@@ -45,14 +45,7 @@ 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,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user