Compare commits
80
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7017bde04d | ||
|
|
7701e7a65a | ||
|
|
65a91832a8 | ||
|
|
acb47ffed5 | ||
|
|
13c0304d84 | ||
|
|
febdf3974c | ||
|
|
390acec928 | ||
|
|
ff806f8c3e | ||
|
|
06c4faabc3 | ||
|
|
92aec16fa3 | ||
|
|
f1ffb783d8 | ||
|
|
b708300586 | ||
|
|
f88d757d06 | ||
|
|
4d96f188d1 | ||
|
|
2d943f40bb | ||
|
|
92c058a736 | ||
|
|
ba819bcfca | ||
|
|
e22f1adfa7 | ||
|
|
f2bca03360 | ||
|
|
5f07d701f0 | ||
|
|
496a50bc89 | ||
|
|
6ccb6c4cce | ||
|
|
42c78fd0a9 | ||
|
|
3d0e2923ae | ||
|
|
408b2371f0 | ||
|
|
6ea08b40a8 | ||
|
|
5eb0f7d3ec | ||
|
|
d465d59c3a | ||
|
|
af9a60d175 | ||
|
|
8e0f0c92ce | ||
|
|
5a14fb4b5d | ||
|
|
22a1aacb21 | ||
|
|
e5b6c11399 | ||
|
|
85ebd67a28 | ||
|
|
f33a779668 | ||
|
|
1b5916b655 | ||
|
|
d8720cd858 | ||
|
|
44636bddaa | ||
|
|
1741723687 | ||
|
|
ad2c291d4a | ||
|
|
52ffd80041 | ||
|
|
44dde744ea | ||
|
|
c18ddf929e | ||
|
|
5661365248 | ||
|
|
bcb9d258c2 | ||
|
|
53a94c4547 | ||
|
|
928ffe94a7 | ||
|
|
dcb78c7144 | ||
|
|
43dd8fa1cc | ||
|
|
91a5f00d30 | ||
|
|
0eff54b807 | ||
|
|
68eb0ce3f1 | ||
|
|
023318c08d | ||
|
|
c0e3aa2b0a | ||
|
|
a6d1b9188f | ||
|
|
43193c5ac5 | ||
|
|
35c58047ee | ||
|
|
2190f3544f | ||
|
|
fd8ea78e04 | ||
|
|
7fc336a6d9 | ||
|
|
3cc6fae5c0 | ||
|
|
f4f75da016 | ||
|
|
bdeba1aa86 | ||
|
|
8991be4eea | ||
|
|
940b93ceb8 | ||
|
|
00eb3d0d4f | ||
|
|
7f61eb7a0a | ||
|
|
53f506670c | ||
|
|
9fe7ab31ed | ||
|
|
008534b8a2 | ||
|
|
2c5842f908 | ||
|
|
a8ee9d473e | ||
|
|
1e3ab83e6a | ||
|
|
9720da2c68 | ||
|
|
ee74e2d50c | ||
|
|
6171009add | ||
|
|
d299a444fa | ||
|
|
107276e9cc | ||
|
|
fe00cbf106 | ||
|
|
02d0ddbcfe |
@@ -1,25 +0,0 @@
|
||||
name: Android
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: armeabi-v7a,arm64-v8a,x86_64
|
||||
@@ -1,29 +0,0 @@
|
||||
name: iOS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-ios
|
||||
path: out/filament-release-ios.tgz
|
||||
- name: Build iOS samples
|
||||
run: |
|
||||
cd build/ios && ./build-samples.sh continuous
|
||||
@@ -1,26 +0,0 @@
|
||||
name: Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
@@ -1,29 +0,0 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
@@ -0,0 +1,59 @@
|
||||
name: 'Postsubmit Tasks'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update-renderdiff-goldens:
|
||||
name: update-renderdiff-goldens
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install tifffile numpy
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
|
||||
run: |
|
||||
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
echo "branch==${GOLDEN_BRANCH}"
|
||||
echo "hash==${COMMIT_HASH}"
|
||||
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
|
||||
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
|
||||
fi
|
||||
|
||||
update-docs:
|
||||
name: update-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install selenium
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
run: |
|
||||
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
|
||||
@@ -1,59 +1,115 @@
|
||||
name: 'Post-submit tasks'
|
||||
name: 'Postsubmit CI'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
update-renderdiff-goldens:
|
||||
name: update-renderdiff-goldens
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install tifffile numpy
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
|
||||
run: |
|
||||
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
echo "branch==${GOLDEN_BRANCH}"
|
||||
echo "hash==${COMMIT_HASH}"
|
||||
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
|
||||
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
|
||||
fi
|
||||
build-android:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
update-docs:
|
||||
name: update-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install selenium
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: armeabi-v7a,arm64-v8a,x86_64
|
||||
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-ios
|
||||
path: out/filament-release-ios.tgz
|
||||
- name: Build iOS samples
|
||||
run: |
|
||||
cd build/ios && ./build-samples.sh continuous
|
||||
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-web
|
||||
path: out/filament-release-web.tgz
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2022-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
shell: cmd
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-windows
|
||||
path: out/filament-windows.tgz
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Presubmit
|
||||
name: 'Presubmit CI'
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh presubmit
|
||||
cd build/mac && printf "y" | ./build.sh presubmit-with-test
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
name: Web
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-web
|
||||
path: out/filament-release-web.tgz
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2022-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
shell: cmd
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-windows
|
||||
path: out/filament-windows.tgz
|
||||
+15
-3
@@ -367,14 +367,22 @@ endif()
|
||||
|
||||
if (LINUX)
|
||||
option(USE_STATIC_LIBCXX "Link against the static runtime libraries." ON)
|
||||
|
||||
# Add this step to support both glibc-based Linux distributions (e.g., Ubuntu, Debian)
|
||||
# and musl-based distributions (e.g., Alpine).
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(__GLIBC__ "features.h" CLANG_WITH_GLIBC)
|
||||
|
||||
if (${USE_STATIC_LIBCXX})
|
||||
if (FILAMENT_USING_GCC)
|
||||
link_libraries("-static-libgcc -static-libstdc++")
|
||||
else ()
|
||||
elseif (CLANG_WITH_GLIBC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
link_libraries("-static-libgcc -static-libstdc++")
|
||||
link_libraries(libc++.a)
|
||||
link_libraries(libc++abi.a)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -473,7 +481,7 @@ endif()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${EXTRA_SANITIZE_OPTIONS}")
|
||||
|
||||
if (FILAMENT_ENABLE_COVERAGE)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping -Wno-pass-failed")
|
||||
endif()
|
||||
|
||||
# Disable the stack check for macOS to workaround a known issue in clang 11.0.0.
|
||||
@@ -563,6 +571,10 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_WEBGPU)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
endif()
|
||||
|
||||
# Build with Metal support on non-WebGL Apple platforms.
|
||||
if (APPLE AND NOT WEBGL)
|
||||
option(FILAMENT_SUPPORTS_METAL "Include the Metal backend" ON)
|
||||
@@ -915,7 +927,6 @@ endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
add_subdirectory(${EXTERNAL}/libwebp/tnt)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
@@ -973,6 +984,7 @@ if (IS_HOST_PLATFORM)
|
||||
add_subdirectory(${TOOLS}/roughness-prefilter)
|
||||
add_subdirectory(${TOOLS}/specular-color)
|
||||
add_subdirectory(${TOOLS}/uberz)
|
||||
add_subdirectory(${TOOLS}/specgen)
|
||||
endif()
|
||||
|
||||
# Generate exported executables for cross-compiled builds (Android, WebGL, and iOS)
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.68.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.68.4'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.68.3'
|
||||
pod 'Filament', '~> 1.68.4'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,6 +7,15 @@ 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
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.68.5
|
||||
|
||||
- engine: "native" Streams are officially deprecated. Use "acquired" streams instead.
|
||||
- engine: add "engine.skip_frame_when_cpu_ahead_of_display" feature [b/474599530]
|
||||
|
||||
## v1.68.4
|
||||
|
||||
- gltfio: Add optional support for webp textures (EXT_texture_webp), controlled via FILAMENT_SUPPORTS_WEBP_TEXTURES cmake option
|
||||
|
||||
## v1.68.3
|
||||
|
||||
- materials: added support for the glTF `KHR_materials_dispersion` extension, which adds dispersion for refractive objects
|
||||
|
||||
@@ -335,6 +335,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefract
|
||||
builder->refractionMode((MaterialBuilder::RefractionMode) mode);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderReflectionMode(JNIEnv* env,
|
||||
jclass, jlong nativeBuilder, jint mode) {
|
||||
auto builder = (MaterialBuilder*) nativeBuilder;
|
||||
builder->reflectionMode((MaterialBuilder::ReflectionMode) mode);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefractionType(JNIEnv* env,
|
||||
jclass, jlong nativeBuilder, jint type) {
|
||||
|
||||
+12
@@ -177,6 +177,11 @@ public class MaterialBuilder {
|
||||
SCREEN_SPACE
|
||||
}
|
||||
|
||||
public enum ReflectionMode {
|
||||
DEFAULT,
|
||||
SCREEN_SPACE
|
||||
}
|
||||
|
||||
public enum RefractionType {
|
||||
SOLID,
|
||||
THIN
|
||||
@@ -403,6 +408,12 @@ public class MaterialBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MaterialBuilder reflectionMode(ReflectionMode mode) {
|
||||
nMaterialBuilderReflectionMode(mNativeObject, mode.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MaterialBuilder refractionType(RefractionType type) {
|
||||
nMaterialBuilderRefractionType(mNativeObject, type.ordinal());
|
||||
@@ -604,6 +615,7 @@ public class MaterialBuilder {
|
||||
private static native void nMaterialBuilderSpecularAntiAliasingThreshold(long mNativeObject,
|
||||
float threshold);
|
||||
private static native void nMaterialBuilderRefractionMode(long nativeBuilder, int mode);
|
||||
private static native void nMaterialBuilderReflectionMode(long nativeBuilder, int mode);
|
||||
private static native void nMaterialBuilderRefractionType(long nativeBuilder, int type);
|
||||
private static native void nMaterialBuilderClearCoatIorChange(long mNativeObject,
|
||||
boolean clearCoatIorChange);
|
||||
|
||||
@@ -2041,10 +2041,6 @@ public class View {
|
||||
* use an AABB neighborhood
|
||||
*/
|
||||
AABB,
|
||||
/**
|
||||
* use the variance of the neighborhood (not recommended)
|
||||
*/
|
||||
VARIANCE,
|
||||
/**
|
||||
* use both AABB and variance
|
||||
*/
|
||||
@@ -2075,7 +2071,7 @@ public class View {
|
||||
}
|
||||
|
||||
/**
|
||||
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
|
||||
* @deprecated has no effect.
|
||||
*/
|
||||
public float filterWidth = 1.0f;
|
||||
/**
|
||||
@@ -2095,9 +2091,9 @@ public class View {
|
||||
*/
|
||||
public boolean enabled = false;
|
||||
/**
|
||||
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
|
||||
* Upscaling factor. Disables Dynamic Resolution. [BETA]
|
||||
*/
|
||||
public boolean upscaling = false;
|
||||
public float upscaling = 1.0f;
|
||||
/**
|
||||
* whether to filter the history buffer
|
||||
*/
|
||||
@@ -2110,6 +2106,10 @@ public class View {
|
||||
* whether to use the YcoCg color-space for history rejection
|
||||
*/
|
||||
public boolean useYCoCg = false;
|
||||
/**
|
||||
* set to true for HDR content
|
||||
*/
|
||||
public boolean hdr = true;
|
||||
/**
|
||||
* type of color gamut box
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,7 @@ option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
|
||||
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
|
||||
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
|
||||
option(FILAMENT_SUPPORTS_WEBP_TEXTURES "Enable webp texture support on Android" OFF)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
@@ -30,6 +31,12 @@ add_library(stb STATIC IMPORTED)
|
||||
set_target_properties(stb PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libstb.a)
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
add_library(webpdecoder STATIC IMPORTED)
|
||||
set_target_properties(webpdecoder PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebpdecoder.a)
|
||||
endif()
|
||||
|
||||
add_library(basis_transcoder STATIC IMPORTED)
|
||||
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
|
||||
@@ -81,6 +88,10 @@ set(GLTFIO_INCLUDE_DIRS
|
||||
../../libs/ktxreader/include
|
||||
)
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
list(APPEND GLTFIO_INCLUDE_DIRS ../../third_party/libwebp/src)
|
||||
endif()
|
||||
|
||||
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
|
||||
|
||||
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
|
||||
@@ -107,3 +118,6 @@ target_link_libraries(gltfio-jni
|
||||
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
|
||||
PRIVATE log # needed only when perfetto above is used
|
||||
)
|
||||
if (FILAMENT_SUPPORTS_WEBP_TEXTURES)
|
||||
target_link_libraries(gltfio-jni PRIVATE webpdecoder)
|
||||
endif()
|
||||
|
||||
@@ -128,6 +128,18 @@ Java_com_google_android_filament_gltfio_ResourceLoader_nCreateKtx2Provider(JNIEn
|
||||
return (jlong) createKtx2Provider(engine);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_gltfio_ResourceLoader_nIsWebpSupported(JNIEnv*, jclass) {
|
||||
return (jboolean) isWebpSupported();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateWebpProvider(JNIEnv*, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jlong) createWebpProvider(engine);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_ResourceLoader_nDestroyTextureProvider(JNIEnv*, jclass,
|
||||
jlong nativeProvider) {
|
||||
|
||||
+23
@@ -37,6 +37,7 @@ public class ResourceLoader {
|
||||
private final long mNativeObject;
|
||||
private final long mNativeStbProvider;
|
||||
private final long mNativeKtx2Provider;
|
||||
private final long mNativeWebpProvider;
|
||||
|
||||
/**
|
||||
* Constructs a resource loader tied to the given Filament engine.
|
||||
@@ -50,9 +51,17 @@ public class ResourceLoader {
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, false);
|
||||
mNativeStbProvider = nCreateStbProvider(nativeEngine);
|
||||
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
|
||||
|
||||
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
|
||||
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
|
||||
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
|
||||
if (nIsWebpSupported()) {
|
||||
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
|
||||
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
|
||||
}
|
||||
else {
|
||||
mNativeWebpProvider = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,9 +77,17 @@ public class ResourceLoader {
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights);
|
||||
mNativeStbProvider = nCreateStbProvider(nativeEngine);
|
||||
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
|
||||
|
||||
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
|
||||
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
|
||||
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
|
||||
if (nIsWebpSupported()) {
|
||||
mNativeWebpProvider = nCreateWebpProvider(nativeEngine);
|
||||
nAddTextureProvider(mNativeObject, "image/webp", mNativeWebpProvider);
|
||||
}
|
||||
else {
|
||||
mNativeWebpProvider = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +97,9 @@ public class ResourceLoader {
|
||||
nDestroyResourceLoader(mNativeObject);
|
||||
nDestroyTextureProvider(mNativeStbProvider);
|
||||
nDestroyTextureProvider(mNativeKtx2Provider);
|
||||
if (nIsWebpSupported()) {
|
||||
nDestroyTextureProvider(mNativeWebpProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +211,9 @@ public class ResourceLoader {
|
||||
|
||||
private static native long nCreateStbProvider(long nativeEngine);
|
||||
private static native long nCreateKtx2Provider(long nativeEngine);
|
||||
private static native boolean nIsWebpSupported();
|
||||
private static native long nCreateWebpProvider(long nativeEngine);
|
||||
|
||||
private static native void nAddTextureProvider(long nativeLoader, String url, long nativeProvider);
|
||||
private static native void nDestroyTextureProvider(long nativeProvider);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.68.3
|
||||
VERSION_NAME=1.68.4
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+38
-18
@@ -76,11 +76,16 @@ class MainActivity : Activity() {
|
||||
private var texture: Texture? = null
|
||||
private var renderTarget: RenderTarget? = null
|
||||
|
||||
private var useExternalTexture = true
|
||||
|
||||
private lateinit var offscreenView: View
|
||||
private lateinit var offscreenCamera: Camera
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// To use set this flag with adb, run
|
||||
// adb shell am start -n com.google.android.filament.texturetarget/.MainActivity --ez useExternalTexture false
|
||||
useExternalTexture = intent.getBooleanExtra("useExternalTexture", true)
|
||||
surfaceView = SurfaceView(this)
|
||||
setContentView(surfaceView)
|
||||
choreographer = Choreographer.getInstance()
|
||||
@@ -173,8 +178,15 @@ class MainActivity : Activity() {
|
||||
readUncompressedAsset("materials/baked_color.filamat").let {
|
||||
triangleMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
readUncompressedAsset("materials/textured.filamat").let {
|
||||
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
|
||||
if (useExternalTexture) {
|
||||
readUncompressedAsset("materials/texturedExternal.filamat").let {
|
||||
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
} else {
|
||||
readUncompressedAsset("materials/textured.filamat").let {
|
||||
texturedMaterial = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,33 +397,41 @@ class MainActivity : Activity() {
|
||||
texture?.let { engine.destroyTexture(it) }
|
||||
hardwareBuffer?.close()
|
||||
|
||||
// Create a new render target.
|
||||
hardwareBuffer = HardwareBuffer.create(width, height,
|
||||
HardwareBuffer.RGBA_8888, 1,
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
|
||||
if (useExternalTexture) {
|
||||
// Create a new render target.
|
||||
hardwareBuffer = HardwareBuffer.create(width, height,
|
||||
HardwareBuffer.RGBA_8888, 1,
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
|
||||
|
||||
texture = Texture.Builder()
|
||||
.width(width)
|
||||
.height(height)
|
||||
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.external()
|
||||
.build(engine)
|
||||
texture = Texture.Builder()
|
||||
.width(width)
|
||||
.height(height)
|
||||
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.external()
|
||||
.build(engine)
|
||||
|
||||
texture!!.setExternalImage(engine, hardwareBuffer!!)
|
||||
texture!!.setExternalImage(engine, hardwareBuffer!!)
|
||||
} else {
|
||||
texture = Texture.Builder()
|
||||
.width(width)
|
||||
.height(height)
|
||||
.levels(1)
|
||||
.usage(Texture.Usage.COLOR_ATTACHMENT or Texture.Usage.SAMPLEABLE)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.build(engine)
|
||||
}
|
||||
|
||||
renderTarget = RenderTarget.Builder()
|
||||
.texture(RenderTarget.AttachmentPoint.COLOR, texture!!)
|
||||
.build(engine)
|
||||
|
||||
offscreenView.renderTarget = renderTarget
|
||||
|
||||
// Set the texture on the quad material.
|
||||
texturedMaterial.defaultInstance.setParameter("texture", texture!!,
|
||||
TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR,
|
||||
TextureSampler.WrapMode.CLAMP_TO_EDGE))
|
||||
|
||||
TextureSampler.WrapMode.CLAMP_TO_EDGE))
|
||||
FilamentHelper.synchronizePendingFrames(engine)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ material {
|
||||
shadingModel : unlit,
|
||||
parameters : [
|
||||
{
|
||||
type : samplerExternal,
|
||||
type : sampler2d,
|
||||
name : texture
|
||||
}
|
||||
],
|
||||
@@ -15,6 +15,6 @@ material {
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = texture(materialParams_texture, getUV0());
|
||||
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
material {
|
||||
name : textured,
|
||||
shadingModel : unlit,
|
||||
parameters : [
|
||||
{
|
||||
type : samplerExternal,
|
||||
name : texture
|
||||
}
|
||||
],
|
||||
requires: [
|
||||
uv0
|
||||
]
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = texture(materialParams_texture, uvToRenderTargetUV(getUV0()));
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,11 @@ if [[ "$TARGET" == "presubmit" ]]; then
|
||||
BUILD_RELEASE=release
|
||||
fi
|
||||
|
||||
if [[ "$TARGET" == "presubmit-with-test" ]]; then
|
||||
BUILD_RELEASE=release
|
||||
RUN_TESTS=-u
|
||||
fi
|
||||
|
||||
if [[ "$TARGET" == "debug" ]]; then
|
||||
BUILD_DEBUG=debug
|
||||
GENERATE_ARCHIVES=-a
|
||||
|
||||
+30
-6
@@ -97,6 +97,7 @@ in table [standardProperties].
|
||||
**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
|
||||
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
|
||||
**microThickness** | Thickness of the thin layer of refractive objects
|
||||
**dispersion** | Strength of the dispersion effect for refractive objects, specified as 20/Abbe number
|
||||
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
|
||||
**shadowStrength** | Strength factor between 0 and 1 for all shadows received by this material
|
||||
[Table [standardProperties]: Properties of the standard model]
|
||||
@@ -126,6 +127,7 @@ The type and range of each property is described in table [standardPropertiesTyp
|
||||
**absorption** | float3 | [0..n] |
|
||||
**microThickness** | float | [0..n] |
|
||||
**thickness** | float | [0..n] |
|
||||
**dispersion** | float | [0..n] | Realistic values are between [0, 1], with the exception of Rutile, which has a value of 2.04
|
||||
[Table [standardPropertiesTypes]: Range and type of the standard model's properties]
|
||||
|
||||
|
||||
@@ -153,13 +155,14 @@ The type and range of each property is described in table [standardPropertiesTyp
|
||||
as-is, which can lead to physically impossible materials, however, this might be desirable
|
||||
for artistic reasons.
|
||||
|
||||
!!! Note: About `thickness` and `microThickness` for refraction
|
||||
!!! Note: About `thickness`, `microThickness` and `dispersion` for refraction
|
||||
`thickness` represents the thickness of solid objects in the direction of the normal, for
|
||||
satisfactory results, this should be provided per fragment (e.g.: as a texture) or at least per
|
||||
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
|
||||
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
|
||||
would have a `thickness` of 1 and a `microThickness` of 0.001. Currently `thickness` is not
|
||||
used when `refractionType` is set to `thin`.
|
||||
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
|
||||
separation of colors transmitting through a volume, and can be set by a constant value.
|
||||
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
|
||||
|
||||
### Base color
|
||||
|
||||
@@ -651,6 +654,26 @@ the `refractionType` is set to `solid` and `absorption` coefficients are set.
|
||||
![Figure [varyingThickness]: `thickness` varying from 0.0 at the top of the prism to 3.0 at the
|
||||
bottom of the prism](images/material_thickness.png)
|
||||
|
||||
### Dispersion
|
||||
|
||||
The dispersion property controls the angular separation of colors transmitting through a relatively
|
||||
clear volume. It can only be used when `refractionType` is set to `volume`.
|
||||
Its value is specified as 20/Abbe number. When the value is zero, no dispersion is used.
|
||||
|
||||
Table [commonMatDispersion] describes acceptable dispersion values for various types of materials.
|
||||
|
||||
Material | Abbe Number (V) | Dispersion (20/V)
|
||||
--------------------------:|:------------------:|:-----------------
|
||||
Rutile | 9.8 | 2.04
|
||||
Polycarbonate | 32 | 0.625
|
||||
Diamond | 55 | 0.36
|
||||
Water | 55 | 0.36
|
||||
Crown Glass | 59 | 0.33
|
||||
[Table [commonMatDispersion]: Dispersion of common materials]
|
||||
|
||||
![Figure [dispersionProperty]: `dispersion` varying from 0.0
|
||||
(left) to 5.0 (right)](images/materials/dispersion.png)
|
||||
|
||||
## Subsurface model
|
||||
|
||||
### Thickness
|
||||
@@ -2276,6 +2299,7 @@ struct MaterialInputs {
|
||||
float3 absorption; // default float3(0.0, 0.0, 0.0)
|
||||
float ior; // default: 1.5
|
||||
float microThickness; // default: 0.0, not available with refractionType "solid"
|
||||
float dispersion; // default: 0.0, not available with refractionType "thin"
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2456,9 +2480,9 @@ type aliases:
|
||||
**uint2** | uvec2 | A vector of 2 unsigned integers
|
||||
**uint3** | uvec3 | A vector of 3 unsigned integers
|
||||
**uint4** | uvec4 | A vector of 4 unsigned integers
|
||||
**float2** | float2 | A vector of 2 floats
|
||||
**float3** | float3 | A vector of 3 floats
|
||||
**float4** | float4 | A vector of 4 floats
|
||||
**float2** | vec2 | A vector of 2 floats
|
||||
**float3** | vec3 | A vector of 3 floats
|
||||
**float4** | vec4 | A vector of 4 floats
|
||||
**float4x4** | mat4 | A 4x4 float matrix
|
||||
**float3x3** | mat3 | A 3x3 float matrix
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Build for Android on Windows - Filament</title>
|
||||
<title>Android on Windows - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -273,7 +273,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../build/maven_release.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -287,7 +287,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../build/maven_release.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -327,12 +327,41 @@ host tools are required to successfully build for Android.</p>
|
||||
<p>Note that the main target is the ARM 64-bit target. Our implementation is optimized first and
|
||||
foremost for <code>arm64-v8a</code>.</p>
|
||||
<p>To build Android on Windows machines, see <a href="android/Windows.html">android/Windows.md</a>.</p>
|
||||
<h4 id="important-sdk-location"><a class="header" href="#important-sdk-location">Important: SDK location</a></h4>
|
||||
<p>Either ensure your <code>ANDROID_HOME</code> environment variable is set or make sure the root project
|
||||
contains a <code>local.properties</code> file with the <code>sdk.dir</code> property pointing to your installation of
|
||||
the Android SDK.</p>
|
||||
<h4 id="easy-android-build"><a class="header" href="#easy-android-build">Easy Android build</a></h4>
|
||||
<p>The easiest way to build Filament for Android is to use <code>build.sh</code> and the
|
||||
<code>-p android</code> flag. For instance to build the release target:</p>
|
||||
<pre><code class="language-shell">./build.sh -p android release
|
||||
</code></pre>
|
||||
<p>To build a sample (such as <code>android/samples/sample-hello-triangle</code>) for an ARM 64-bit phone, you would run</p>
|
||||
<pre><code class="language-shell">./build.sh -p android -q arm64-v8a -k sample-hello-triangle release
|
||||
</code></pre>
|
||||
<p>The output APK can be found in <code>android/samples/sample-hello-triangle/build/outputs/apk/release/sample-hello-triangle-release-unsigned.apk</code></p>
|
||||
<p>Run <code>build.sh -h</code> for more information.</p>
|
||||
<h4 id="android-studio"><a class="header" href="#android-studio">Android Studio</a></h4>
|
||||
<p>You must use the latest stable release of Android Studio.</p>
|
||||
<p>The Android build of filament is separated into java/kotlin client APIs, a layer of jni bindings
|
||||
that bridges java/kotlin with native code, and Filament and other component code that have been compiled
|
||||
into architecture-specific libraries. Our default Android Studio gradle setup can compile java/kotlin and
|
||||
the jni bindings for you, but it will treat the filament libraries as already compiled and present on
|
||||
the system.</p>
|
||||
<p>Therefore, before compiling the sample app or any other targets, you must
|
||||
make sure that the native filament libraries have been compiled and are located at a prescribed location
|
||||
so that the jni bindings can link against them. You can do so by using the easy build script</p>
|
||||
<pre><code class="language-shell">./build.sh -p android release -q arm64-v8a
|
||||
</code></pre>
|
||||
<p>Note that the above step will also install host machine tools into prescribed locations. These tools are
|
||||
required for compiling Filament assets such as materials and environment maps.</p>
|
||||
<p>Now we are ready to compile the apps. To open the project, point Studio to the <code>android</code> folder.
|
||||
After opening the project and syncing with Gradle, select the sample of your choice
|
||||
using the drop-down widget in the toolbar. Additionally, you will need to select a deployment target.
|
||||
By doing so, Android Studio will automatically try to compile the app only for that specific
|
||||
device's architecture. So if you are targeting a new Pixel phone, make sure that the step above
|
||||
(compiling the library) is targeting ARM 64-bit (<code>-q arm64-v8a</code> ), and if you are running the app on
|
||||
an emulator on a Linux machine with an x86 64-bit chipset, you would indicate (<code>-q x86_64</code>) in the above step.</p>
|
||||
<h4 id="manual-builds"><a class="header" href="#manual-builds">Manual builds</a></h4>
|
||||
<p>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 (<code>aarch64</code>).</p>
|
||||
|
||||
@@ -209,7 +209,7 @@ as possible. The current external dependencies of the runtime library include:</
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../build/maven_release.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -223,7 +223,7 @@ as possible. The current external dependencies of the runtime library include:</
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../build/maven_release.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
+3
-3
@@ -203,7 +203,7 @@ tree into <code>docs_src/src_mdbook/src/dup</code>. Moreover, to restore valid l
|
||||
to perform a number of URL replacements in addition to the copy. These replacements are
|
||||
described in <a href="https://github.com/google/filament/blob/main/docs_src/build/duplicates.json"><code>docs_src/build/duplicates.json</code></a>.</p>
|
||||
<h3 id="core-concept-docs"><a class="header" href="#core-concept-docs">Core concept docs</a></h3>
|
||||
<p>The primary design of Filament as a phyiscally-based renderer and details of its materials
|
||||
<p>The primary design of Filament as a physically-based renderer and details of its materials
|
||||
system are described in <code>Filament.md.html</code> and <code>Materials.md.html</code>, respectively. These two
|
||||
documents are written in <a href="https://casual-effects.com/markdeep/"><code>markdeep</code></a>. To embed them into our book, we</p>
|
||||
<ol>
|
||||
@@ -253,7 +253,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/release_guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -267,7 +267,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/release_guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.68.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.68.4'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -196,7 +196,7 @@ dependencies {
|
||||
</div>
|
||||
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
|
||||
<p>iOS projects can use CocoaPods to install the latest release:</p>
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.68.0'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.68.4'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>backend - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="backend-tests"><a class="header" href="#backend-tests">Backend Tests</a></h1>
|
||||
<p>This directory (<code>/test/backend</code>) contains scripts to run Filament's backend tests using a software
|
||||
rasterizer (Mesa). This is useful for running tests in a continuous integration environment where a
|
||||
GPU might not be available.</p>
|
||||
<p>The <code>test.sh</code> script will:</p>
|
||||
<ol>
|
||||
<li>Build Mesa if needed.</li>
|
||||
<li>Build the backend tests.</li>
|
||||
<li>Run the tests using the OpenGL and Vulkan backends with Mesa.</li>
|
||||
</ol>
|
||||
<h2 id="flags"><a class="header" href="#flags">Flags</a></h2>
|
||||
<p>The <code>test.sh</code> script accepts the following flags:</p>
|
||||
<ul>
|
||||
<li><code>--gtest_filter</code>: Filters the tests that are run. This is passed directly to the underlying
|
||||
gtest executable.</li>
|
||||
<li><code>--backend</code>: Specifies which backend to test. Can be <code>opengl</code>, <code>vulkan</code>, or a comma-separated
|
||||
list (e.g., <code>opengl,vulkan</code>). Defaults to both.</li>
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -159,7 +159,8 @@
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
|
||||
<p>This tool is a collections of scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
|
||||
<p>This tool (<code>/test/renderdiff</code>) is a collections of scripts to run <code>gltf_viewer</code> and produce headless
|
||||
renderings.</p>
|
||||
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
|
||||
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s
|
||||
software rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>.
|
||||
@@ -251,7 +252,7 @@ git switch -c my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>In the commit message of your working branch on <code>filament</code>, add the following line
|
||||
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
|
||||
<pre><code>RDIFF_BRANCH=my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -292,7 +293,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_backend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -306,7 +307,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_backend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 MiB |
+2732
-2773
File diff suppressed because one or more lines are too long
+1903
-1902
File diff suppressed because one or more lines are too long
@@ -165,7 +165,7 @@
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../dup/renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../dup/renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -668,7 +668,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -682,7 +682,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -170,7 +170,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/test_backend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -184,7 +184,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/test_backend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -185,11 +185,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/release_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -199,11 +199,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/release_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -0,0 +1,249 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>CocoaPods - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="filament-cocoapods"><a class="header" href="#filament-cocoapods">Filament CocoaPods</a></h1>
|
||||
<p><a href="https://cocoapods.org/">CocoaPods</a> is the dependency manager Filament uses for Apple platforms
|
||||
(macOS and iOS).</p>
|
||||
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
|
||||
<p>On macOS, CocoaPods requires a modern Ruby environment. Avoid using the system Ruby; instead,
|
||||
install the latest Ruby version using <code>brew</code>, <code>port,</code> or use a manager like <code>rbenv</code> or <code>rvm</code>. Once
|
||||
Ruby is configured:</p>
|
||||
<pre><code class="language-bash">gem install cocoapods
|
||||
</code></pre>
|
||||
<h2 id="linting-the-podspec"><a class="header" href="#linting-the-podspec">Linting the Podspec</a></h2>
|
||||
<p>The Filament podspec is configured to fetch releases directly from GitHub. Before deployment,
|
||||
CocoaPods must <strong>lint</strong> the spec to validate that the library compiles and links correctly across
|
||||
all supported architectures.</p>
|
||||
<p>To run the linter locally:</p>
|
||||
<pre><code class="language-bash">cd ios/CocoaPods/
|
||||
pod spec lint
|
||||
</code></pre>
|
||||
<h3 id="debugging-failures"><a class="header" href="#debugging-failures">Debugging Failures</a></h3>
|
||||
<p>If the lint fails, use the <code>--verbose</code> flag to inspect the underlying <code>xcodebuild</code> output:</p>
|
||||
<pre><code class="language-bash">pod spec lint --verbose
|
||||
</code></pre>
|
||||
<h2 id="isolating-subspecs"><a class="header" href="#isolating-subspecs">Isolating Subspecs</a></h2>
|
||||
<p>Filament is partitioned into multiple <strong>subspecs</strong>. CocoaPods lints these individually. To
|
||||
accelerate debugging or isolate a specific build failure (e.g., <code>Filament/filament</code>), use the
|
||||
following command:</p>
|
||||
<pre><code class="language-bash">pod spec lint --no-clean --verbose --subspec=Filament/filament 2>&1 | tee lint_output.log
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li><code>--no-clean</code>: Preserves the temporary Xcode workspace and build artifacts in <code>/var/folders/...</code>
|
||||
for inspection.</li>
|
||||
<li><code>--verbose</code>: Prints the full compiler and linker invocations.</li>
|
||||
<li><code>--subspec</code>: Limits the scope of the lint to a specific component.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p><strong>Tip:</strong> To view all defined subspecs, grep the podspec file:
|
||||
<code>grep "spec.subspec" ios/CocoaPods/Filament.podspec</code></p>
|
||||
</blockquote>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../release/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/maven.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../release/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/maven.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Release Guide - Filament</title>
|
||||
<title>Github - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -250,11 +250,11 @@ release (for example, v1.42.2).</p>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/maven.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -264,11 +264,11 @@ release (for example, v1.42.2).</p>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/maven.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -0,0 +1,215 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Release - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="release"><a class="header" href="#release">Release</a></h1>
|
||||
<p>This is a collection of guides for releasing Filament on different distribution platforms, including
|
||||
Github, Maven, and CocoaPods.</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/cocoapods.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/cocoapods.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Maven Release - Filament</title>
|
||||
<title>Maven - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -218,11 +218,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/cocoapods.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -232,11 +232,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/cocoapods.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -186,11 +186,11 @@ post-process materials. However for now these two numbers must be set to the sam
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -200,11 +200,11 @@ post-process materials. However for now these two numbers must be set to the sam
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
|
||||
asyncInterval: 30
|
||||
};
|
||||
|
||||
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
|
||||
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
|
||||
this.srcBlobResources = {};
|
||||
resourceLoader.asyncBeginLoad(this.asset);
|
||||
const timer = setInterval(() => {
|
||||
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
|
||||
resourceLoader.delete();
|
||||
stbProvider.delete();
|
||||
ktx2Provider.delete();
|
||||
if (webpProvider) {
|
||||
webpProvider.delete();
|
||||
}
|
||||
this.animator = this.asset.getInstance().getAnimator();
|
||||
this.animationStartTime = Date.now();
|
||||
}
|
||||
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
|
||||
|
||||
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
|
||||
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
|
||||
let webpProvider = null;
|
||||
|
||||
resourceLoader.addStbProvider("image/jpeg", stbProvider);
|
||||
resourceLoader.addStbProvider("image/png", stbProvider);
|
||||
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
|
||||
|
||||
|
||||
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
|
||||
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
|
||||
resourceLoader.addWebpProvider("image/webp", webpProvider);
|
||||
}
|
||||
|
||||
let remaining = Object.keys(this.srcBlobResources).length;
|
||||
for (const name in this.srcBlobResources) {
|
||||
this.srcBlobResources[name].arrayBuffer().then(buffer => {
|
||||
const desc = getBufferDescriptor(new Uint8Array(buffer));
|
||||
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
|
||||
if (--remaining === 0) {
|
||||
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
|
||||
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ to perform a number of URL replacements in addition to the copy. These replaceme
|
||||
described in [`docs_src/build/duplicates.json`].
|
||||
|
||||
### Core concept docs
|
||||
The primary design of Filament as a phyiscally-based renderer and details of its materials
|
||||
The primary design of Filament as a physically-based renderer and details of its materials
|
||||
system are described in `Filament.md.html` and `Materials.md.html`, respectively. These two
|
||||
documents are written in [`markdeep`]. To embed them into our book, we
|
||||
1. Convert the markdeep into html
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
"libs/fgviewer/README.md": {
|
||||
"dest": "dup/fgviewer.md"
|
||||
},
|
||||
"ios/CocoaPods/README.md": {
|
||||
"dest": "release/cocoapods.md"
|
||||
},
|
||||
"tools/normal-blending/README.md": {
|
||||
"dest": "dup/normal_blending.md"
|
||||
},
|
||||
@@ -83,9 +86,12 @@
|
||||
"dest": "dup/docs.md"
|
||||
},
|
||||
"test/renderdiff/README.md": {
|
||||
"dest": "dup/renderdiff.md",
|
||||
"dest": "dup/test_renderdiff.md",
|
||||
"link_transforms": {
|
||||
"docs/images/": "../images/"
|
||||
}
|
||||
},
|
||||
"test/backend/README.md": {
|
||||
"dest": "dup/test_backend.md"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ sortedcontainers==2.4.0
|
||||
trio==0.31.0
|
||||
trio-websocket==0.12.2
|
||||
typing_extensions==4.15.0
|
||||
urllib3==2.6.0
|
||||
urllib3==2.6.3
|
||||
websocket-client==1.9.0
|
||||
wsproto==1.2.0
|
||||
|
||||
@@ -161,7 +161,7 @@ The type and range of each property is described in table [standardPropertiesTyp
|
||||
vertex. `microThickness` represent the thickness of the thin layer of an object, and can
|
||||
generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m,
|
||||
would have a `thickness` of 1 and a `microThickness` of 0.001. Dispersion controls the angular
|
||||
separation of colors transmitting through a volume, and can be set by a contant value.
|
||||
separation of colors transmitting through a volume, and can be set by a constant value.
|
||||
Currently `thickness` and `dispersion` are not used when `refractionType` is set to `thin`.
|
||||
|
||||
### Base color
|
||||
@@ -671,6 +671,9 @@ Water | 55 | 0.36
|
||||
Crown Glass | 59 | 0.33
|
||||
[Table [commonMatDispersion]: Dispersion of common materials]
|
||||
|
||||
![Figure [dispersionProperty]: `dispersion` varying from 0.0
|
||||
(left) to 5.0 (right)](images/materials/dispersion.png)
|
||||
|
||||
## Subsurface model
|
||||
|
||||
### Thickness
|
||||
@@ -2477,9 +2480,9 @@ type aliases:
|
||||
**uint2** | uvec2 | A vector of 2 unsigned integers
|
||||
**uint3** | uvec3 | A vector of 3 unsigned integers
|
||||
**uint4** | uvec4 | A vector of 4 unsigned integers
|
||||
**float2** | float2 | A vector of 2 floats
|
||||
**float3** | float3 | A vector of 3 floats
|
||||
**float4** | float4 | A vector of 4 floats
|
||||
**float2** | vec2 | A vector of 2 floats
|
||||
**float3** | vec3 | A vector of 3 floats
|
||||
**float4** | vec4 | A vector of 4 floats
|
||||
**float4x4** | mat4 | A 4x4 float matrix
|
||||
**float3x3** | mat3 | A 3x3 float matrix
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
- [Introduction](./dup/intro.md)
|
||||
- [Build](./dup/building.md)
|
||||
- [Build for Android on Windows](./build/windows_android.md)
|
||||
- [Maven Release](./build/maven_release.md)
|
||||
- [Android on Windows](./build/windows_android.md)
|
||||
- [Contribute](./dup/contributing.md)
|
||||
- [Coding Style](./dup/code_style.md)
|
||||
- [Core Concepts](./main/README.md)
|
||||
@@ -14,9 +13,12 @@
|
||||
- [Web Tutorial](./samples/web.md)
|
||||
- [Technical Notes](./notes/README.md)
|
||||
- [Material Properties](./notes/material_properties.md)
|
||||
- [Versioning](./notes/versioning.md)
|
||||
- [Branching](./notes/branching.md)
|
||||
- [Release Guide](./notes/release_guide.md)
|
||||
- [Release](./release/README.md)
|
||||
- [CocoaPods](./release/cocoapods.md)
|
||||
- [Maven](./release/maven.md)
|
||||
- [Github](./release/guide.md)
|
||||
- [Versioning](./release/versioning.md)
|
||||
- [Branching](./release/branching.md)
|
||||
- [Documentation](./dup/docs.md)
|
||||
- [Debugging](./notes/debugging.md)
|
||||
- [Metal](./notes/metal_debugging.md)
|
||||
@@ -28,7 +30,8 @@
|
||||
- [Performance analysis](./notes/performance_analysis.md)
|
||||
- [Framegraph](./notes/framegraph.md)
|
||||
- [Tests](./notes/tests.md)
|
||||
- [renderdiff](./dup/renderdiff.md)
|
||||
- [backend](./dup/test_backend.md)
|
||||
- [renderdiff](./dup/test_renderdiff.md)
|
||||
- [Libraries](./notes/libs.md)
|
||||
- [bluegl](./dup/bluegl.md)
|
||||
- [bluevk](./dup/bluevk.md)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 MiB |
@@ -0,0 +1,4 @@
|
||||
# Release
|
||||
|
||||
This is a collection of guides for releasing Filament on different distribution platforms, including
|
||||
Github, Maven, and CocoaPods.
|
||||
@@ -307,7 +307,7 @@ class FilamentViewer extends LitElement {
|
||||
asyncInterval: 30
|
||||
};
|
||||
|
||||
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider) => {
|
||||
const doneAddingResources = (resourceLoader, stbProvider, ktx2Provider, webpProvider) => {
|
||||
this.srcBlobResources = {};
|
||||
resourceLoader.asyncBeginLoad(this.asset);
|
||||
const timer = setInterval(() => {
|
||||
@@ -318,6 +318,9 @@ class FilamentViewer extends LitElement {
|
||||
resourceLoader.delete();
|
||||
stbProvider.delete();
|
||||
ktx2Provider.delete();
|
||||
if (webpProvider) {
|
||||
webpProvider.delete();
|
||||
}
|
||||
this.animator = this.asset.getInstance().getAnimator();
|
||||
this.animationStartTime = Date.now();
|
||||
}
|
||||
@@ -335,18 +338,25 @@ class FilamentViewer extends LitElement {
|
||||
|
||||
const stbProvider = new Filament.gltfio$StbProvider(this.engine);
|
||||
const ktx2Provider = new Filament.gltfio$Ktx2Provider(this.engine);
|
||||
let webpProvider = null;
|
||||
|
||||
resourceLoader.addStbProvider("image/jpeg", stbProvider);
|
||||
resourceLoader.addStbProvider("image/png", stbProvider);
|
||||
resourceLoader.addKtx2Provider("image/ktx2", ktx2Provider);
|
||||
|
||||
|
||||
if (Filament.gltfio$WebpProvider.isWebpSupported()) {
|
||||
webpProvider = new Filament.gltfio$WebpProvider(this.engine);
|
||||
resourceLoader.addWebpProvider("image/webp", webpProvider);
|
||||
}
|
||||
|
||||
let remaining = Object.keys(this.srcBlobResources).length;
|
||||
for (const name in this.srcBlobResources) {
|
||||
this.srcBlobResources[name].arrayBuffer().then(buffer => {
|
||||
const desc = getBufferDescriptor(new Uint8Array(buffer));
|
||||
resourceLoader.addResourceData(name, getBufferDescriptor(desc));
|
||||
if (--remaining === 0) {
|
||||
doneAddingResources(resourceLoader, stbProvider, ktx2Provider);
|
||||
doneAddingResources(resourceLoader, stbProvider, ktx2Provider, webpProvider);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ set(SRCS
|
||||
src/RenderableManager.cpp
|
||||
src/Renderer.cpp
|
||||
src/RendererUtils.cpp
|
||||
src/ResourceAllocator.cpp
|
||||
src/ResourceList.cpp
|
||||
src/Scene.cpp
|
||||
src/ShadowMap.cpp
|
||||
@@ -108,6 +107,7 @@ set(SRCS
|
||||
src/SwapChain.cpp
|
||||
src/Sync.cpp
|
||||
src/Texture.cpp
|
||||
src/TextureCache.cpp
|
||||
src/ToneMapper.cpp
|
||||
src/TransformManager.cpp
|
||||
src/UniformBuffer.cpp
|
||||
@@ -158,6 +158,7 @@ set(SRCS
|
||||
src/fg/FrameGraphTexture.cpp
|
||||
src/fg/PassNode.cpp
|
||||
src/fg/ResourceNode.cpp
|
||||
src/fg/ResourceCreationContext.cpp
|
||||
src/fsr.cpp
|
||||
src/ZstdHelper.cpp
|
||||
)
|
||||
@@ -168,6 +169,7 @@ set(PRIVATE_HDRS
|
||||
src/Bimap.h
|
||||
src/BufferPoolAllocator.h
|
||||
src/ColorSpaceUtils.h
|
||||
src/compact.h
|
||||
src/Culler.h
|
||||
src/DFG.h
|
||||
src/FilamentAPI-impl.h
|
||||
@@ -188,16 +190,17 @@ set(PRIVATE_HDRS
|
||||
src/RenderPass.h
|
||||
src/RenderPrimitive.h
|
||||
src/RendererUtils.h
|
||||
src/ResourceAllocator.h
|
||||
src/ResourceList.h
|
||||
src/ShadowMap.h
|
||||
src/ShadowMapManager.h
|
||||
src/SharedHandle.h
|
||||
src/TextureCache.h
|
||||
src/UniformBuffer.h
|
||||
src/components/CameraManager.h
|
||||
src/components/LightManager.h
|
||||
src/components/RenderableManager.h
|
||||
src/components/TransformManager.h
|
||||
src/details/AsyncHelpers.h
|
||||
src/details/BufferAllocator.h
|
||||
src/details/BufferObject.h
|
||||
src/details/Camera.h
|
||||
@@ -232,6 +235,7 @@ set(PRIVATE_HDRS
|
||||
src/ds/TypedUniformBuffer.h
|
||||
src/fg/Blackboard.h
|
||||
src/fg/FrameGraph.h
|
||||
src/fg/FrameGraphDummyLink.h
|
||||
src/fg/FrameGraphId.h
|
||||
src/fg/FrameGraphPass.h
|
||||
src/fg/FrameGraphRenderPass.h
|
||||
@@ -241,6 +245,7 @@ set(PRIVATE_HDRS
|
||||
src/fg/details/DependencyGraph.h
|
||||
src/fg/details/PassNode.h
|
||||
src/fg/details/Resource.h
|
||||
src/fg/details/ResourceAllocator.h
|
||||
src/fg/details/ResourceNode.h
|
||||
src/fg/details/Utilities.h
|
||||
src/fsr.h
|
||||
|
||||
@@ -17,6 +17,14 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
#define TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
// Disable the weak-vtables warning because we need the destructor to be inlined in the headers. It
|
||||
// is not optimal (for build), but we have clients that compile their libraries (filament) and app
|
||||
// in different rtti settings.
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
@@ -69,4 +77,8 @@ protected:
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
|
||||
@@ -499,7 +499,7 @@ using descriptor_set_t = uint8_t;
|
||||
|
||||
using descriptor_binding_t = uint8_t;
|
||||
|
||||
struct DescriptorSetLayoutBinding {
|
||||
struct DescriptorSetLayoutDescriptor {
|
||||
static bool isSampler(DescriptorType type) noexcept {
|
||||
return int(type) <= int(DescriptorType::SAMPLER_EXTERNAL);
|
||||
}
|
||||
@@ -513,8 +513,8 @@ struct DescriptorSetLayoutBinding {
|
||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||
uint16_t count = 0;
|
||||
|
||||
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||
friend bool operator==(DescriptorSetLayoutDescriptor const& lhs,
|
||||
DescriptorSetLayoutDescriptor const& rhs) noexcept {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.flags == rhs.flags &&
|
||||
lhs.count == rhs.count &&
|
||||
@@ -1009,98 +1009,99 @@ enum class CompressedPixelDataType : uint16_t {
|
||||
*
|
||||
* @see Texture
|
||||
*/
|
||||
// The [index] comments indicate the corresponding uint16_t values.
|
||||
enum class TextureFormat : uint16_t {
|
||||
// 8-bits per element
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8,
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8, // [0 - 4]
|
||||
|
||||
// 16-bits per element
|
||||
R16F, R16UI, R16I,
|
||||
RG8, RG8_SNORM, RG8UI, RG8I,
|
||||
RGB565,
|
||||
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons.
|
||||
RGB5_A1,
|
||||
RGBA4,
|
||||
DEPTH16,
|
||||
R16F, R16UI, R16I, // [5 - 7]
|
||||
RG8, RG8_SNORM, RG8UI, RG8I, // [8 - 11]
|
||||
RGB565, // [12]
|
||||
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons. [13]
|
||||
RGB5_A1, // [14]
|
||||
RGBA4, // [15]
|
||||
DEPTH16, // [16]
|
||||
|
||||
// 24-bits per element
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I,
|
||||
DEPTH24,
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, // [17 - 21]
|
||||
DEPTH24, // [22]
|
||||
|
||||
// 32-bits per element
|
||||
R32F, R32UI, R32I,
|
||||
RG16F, RG16UI, RG16I,
|
||||
R11F_G11F_B10F,
|
||||
RGBA8, SRGB8_A8,RGBA8_SNORM,
|
||||
UNUSED, // used to be rgbm
|
||||
RGB10_A2, RGBA8UI, RGBA8I,
|
||||
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8,
|
||||
R32F, R32UI, R32I, // [23 - 25]
|
||||
RG16F, RG16UI, RG16I, // [26 - 28]
|
||||
R11F_G11F_B10F, // [29]
|
||||
RGBA8, SRGB8_A8,RGBA8_SNORM, // [30 - 32]
|
||||
UNUSED, // used to be rgbm [33]
|
||||
RGB10_A2, RGBA8UI, RGBA8I, // [34 - 36]
|
||||
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8, // [37 - 39]
|
||||
|
||||
// 48-bits per element
|
||||
RGB16F, RGB16UI, RGB16I,
|
||||
RGB16F, RGB16UI, RGB16I, // [40 - 42]
|
||||
|
||||
// 64-bits per element
|
||||
RG32F, RG32UI, RG32I,
|
||||
RGBA16F, RGBA16UI, RGBA16I,
|
||||
RG32F, RG32UI, RG32I, // [43 - 45]
|
||||
RGBA16F, RGBA16UI, RGBA16I, // [46 - 48]
|
||||
|
||||
// 96-bits per element
|
||||
RGB32F, RGB32UI, RGB32I,
|
||||
RGB32F, RGB32UI, RGB32I, // [49 - 51]
|
||||
|
||||
// 128-bits per element
|
||||
RGBA32F, RGBA32UI, RGBA32I,
|
||||
RGBA32F, RGBA32UI, RGBA32I, // [52 - 54]
|
||||
|
||||
// compressed formats
|
||||
|
||||
// Mandatory in GLES 3.0 and GL 4.3
|
||||
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED,
|
||||
ETC2_RGB8, ETC2_SRGB8,
|
||||
ETC2_RGB8_A1, ETC2_SRGB8_A1,
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8,
|
||||
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, // [55 - 58]
|
||||
ETC2_RGB8, ETC2_SRGB8, // [59 - 60]
|
||||
ETC2_RGB8_A1, ETC2_SRGB8_A1, // [61 - 62]
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, // [63 - 64]
|
||||
|
||||
// Available everywhere except Android/iOS
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, // [65 - 68]
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, // [69 - 72]
|
||||
|
||||
// ASTC formats are available with a GLES extension
|
||||
RGBA_ASTC_4x4,
|
||||
RGBA_ASTC_5x4,
|
||||
RGBA_ASTC_5x5,
|
||||
RGBA_ASTC_6x5,
|
||||
RGBA_ASTC_6x6,
|
||||
RGBA_ASTC_8x5,
|
||||
RGBA_ASTC_8x6,
|
||||
RGBA_ASTC_8x8,
|
||||
RGBA_ASTC_10x5,
|
||||
RGBA_ASTC_10x6,
|
||||
RGBA_ASTC_10x8,
|
||||
RGBA_ASTC_10x10,
|
||||
RGBA_ASTC_12x10,
|
||||
RGBA_ASTC_12x12,
|
||||
SRGB8_ALPHA8_ASTC_4x4,
|
||||
SRGB8_ALPHA8_ASTC_5x4,
|
||||
SRGB8_ALPHA8_ASTC_5x5,
|
||||
SRGB8_ALPHA8_ASTC_6x5,
|
||||
SRGB8_ALPHA8_ASTC_6x6,
|
||||
SRGB8_ALPHA8_ASTC_8x5,
|
||||
SRGB8_ALPHA8_ASTC_8x6,
|
||||
SRGB8_ALPHA8_ASTC_8x8,
|
||||
SRGB8_ALPHA8_ASTC_10x5,
|
||||
SRGB8_ALPHA8_ASTC_10x6,
|
||||
SRGB8_ALPHA8_ASTC_10x8,
|
||||
SRGB8_ALPHA8_ASTC_10x10,
|
||||
SRGB8_ALPHA8_ASTC_12x10,
|
||||
SRGB8_ALPHA8_ASTC_12x12,
|
||||
RGBA_ASTC_4x4, // [73]
|
||||
RGBA_ASTC_5x4, // [74]
|
||||
RGBA_ASTC_5x5, // [75]
|
||||
RGBA_ASTC_6x5, // [76]
|
||||
RGBA_ASTC_6x6, // [77]
|
||||
RGBA_ASTC_8x5, // [78]
|
||||
RGBA_ASTC_8x6, // [79]
|
||||
RGBA_ASTC_8x8, // [80]
|
||||
RGBA_ASTC_10x5, // [81]
|
||||
RGBA_ASTC_10x6, // [82]
|
||||
RGBA_ASTC_10x8, // [83]
|
||||
RGBA_ASTC_10x10, // [84]
|
||||
RGBA_ASTC_12x10, // [85]
|
||||
RGBA_ASTC_12x12, // [86]
|
||||
SRGB8_ALPHA8_ASTC_4x4, // [87]
|
||||
SRGB8_ALPHA8_ASTC_5x4, // [88]
|
||||
SRGB8_ALPHA8_ASTC_5x5, // [89]
|
||||
SRGB8_ALPHA8_ASTC_6x5, // [90]
|
||||
SRGB8_ALPHA8_ASTC_6x6, // [91]
|
||||
SRGB8_ALPHA8_ASTC_8x5, // [92]
|
||||
SRGB8_ALPHA8_ASTC_8x6, // [93]
|
||||
SRGB8_ALPHA8_ASTC_8x8, // [94]
|
||||
SRGB8_ALPHA8_ASTC_10x5, // [95]
|
||||
SRGB8_ALPHA8_ASTC_10x6, // [96]
|
||||
SRGB8_ALPHA8_ASTC_10x8, // [97]
|
||||
SRGB8_ALPHA8_ASTC_10x10, // [98]
|
||||
SRGB8_ALPHA8_ASTC_12x10, // [99]
|
||||
SRGB8_ALPHA8_ASTC_12x12, // [100]
|
||||
|
||||
// RGTC formats available with a GLES extension
|
||||
RED_RGTC1, // BC4 unsigned
|
||||
SIGNED_RED_RGTC1, // BC4 signed
|
||||
RED_GREEN_RGTC2, // BC5 unsigned
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed
|
||||
RED_RGTC1, // BC4 unsigned [101]
|
||||
SIGNED_RED_RGTC1, // BC4 signed [102]
|
||||
RED_GREEN_RGTC2, // BC5 unsigned [103]
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed [104]
|
||||
|
||||
// BPTC formats available with a GLES extension
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
|
||||
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
|
||||
RGBA_BPTC_UNORM, // BC7
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed [105]
|
||||
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned [106]
|
||||
RGBA_BPTC_UNORM, // BC7 [107]
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB [108]
|
||||
};
|
||||
|
||||
TextureType getTextureType(TextureFormat format) noexcept;
|
||||
@@ -1385,7 +1386,7 @@ static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
std::variant<utils::StaticString, utils::CString, std::monostate> label;
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutDescriptor> descriptors;
|
||||
};
|
||||
|
||||
//! blending equation function
|
||||
@@ -1715,6 +1716,12 @@ using CompositorTiming = Platform::CompositorTiming;
|
||||
|
||||
using AsynchronousMode = Platform::AsynchronousMode;
|
||||
|
||||
using AsyncCallId = uint32_t;
|
||||
|
||||
static constexpr AsyncCallId InvalidAsyncCallId = std::numeric_limits<AsyncCallId>::max();
|
||||
|
||||
using AsynchronousMode = Platform::AsynchronousMode;
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::ShaderStageFlags>
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace utils {
|
||||
class FeatureFlagManager;
|
||||
}
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class CallbackHandler;
|
||||
@@ -104,6 +108,11 @@ public:
|
||||
/** duration in nanosecond on the std::steady_clock */
|
||||
using duration_ns = int64_t;
|
||||
static constexpr time_point_ns INVALID = -1; //!< value not supported
|
||||
/**
|
||||
* The time delta [ns] between subsequent composition events.
|
||||
*/
|
||||
duration_ns compositeInterval;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the next time the compositor will begin composition.
|
||||
* This is effectively the deadline for when the compositor must receive a newly queued
|
||||
@@ -111,11 +120,6 @@ public:
|
||||
*/
|
||||
time_point_ns compositeDeadline;
|
||||
|
||||
/**
|
||||
* The time delta [ns] between subsequent composition events.
|
||||
*/
|
||||
duration_ns compositeInterval;
|
||||
|
||||
/**
|
||||
* The time delta [ns] between the start of composition and the expected present time of
|
||||
* that composition. This can be used to estimate the latency of the actual present time.
|
||||
@@ -123,22 +127,9 @@ public:
|
||||
duration_ns compositeToPresentLatency;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the system's expected presentation time.
|
||||
* INVALID if not supported.
|
||||
* Expected latency [ns] of frame presentation relative to vsync.
|
||||
*/
|
||||
time_point_ns expectedPresentTime;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the current frame's start (i.e. vsync)
|
||||
* INVALID if not supported.
|
||||
*/
|
||||
time_point_ns frameTime;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the current frame's deadline
|
||||
* INVALID if not supported.
|
||||
*/
|
||||
time_point_ns frameTimelineDeadline;
|
||||
duration_ns expectedPresentLatency;
|
||||
};
|
||||
|
||||
struct FrameTimestamps {
|
||||
@@ -278,6 +269,11 @@ public:
|
||||
};
|
||||
|
||||
struct DriverConfig {
|
||||
/**
|
||||
* Reference to the system's FeatureFlagManager. Can be nullptr.
|
||||
*/
|
||||
utils::FeatureFlagManager const * UTILS_NULLABLE featureFlagManager = nullptr;
|
||||
|
||||
/**
|
||||
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
|
||||
* Driver clamps to valid values.
|
||||
@@ -288,7 +284,8 @@ public:
|
||||
|
||||
/**
|
||||
* Set to `true` to forcibly disable parallel shader compilation in the backend.
|
||||
* Currently only honored by the GL and Metal backends.
|
||||
* Currently only honored by the GL and Metal backends, and the Vulkan backend
|
||||
* when some experimental features are enabled.
|
||||
*/
|
||||
bool disableParallelShaderCompile = false;
|
||||
|
||||
@@ -319,6 +316,12 @@ public:
|
||||
*/
|
||||
StereoscopicType stereoscopicType = StereoscopicType::NONE;
|
||||
|
||||
/*
|
||||
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
|
||||
* between 1 and Engine::getMaxStereoscopicEyes() (inclusive).
|
||||
*/
|
||||
uint8_t stereoscopicEyeCount = 2;
|
||||
|
||||
/**
|
||||
* Assert the native window associated to a SwapChain is valid when calling makeCurrent().
|
||||
* This is only supported for:
|
||||
@@ -340,6 +343,17 @@ public:
|
||||
*/
|
||||
GpuContextPriority gpuContextPriority = GpuContextPriority::DEFAULT;
|
||||
|
||||
/**
|
||||
* Enables asynchronous pipeline cache preloading, if supported on this device.
|
||||
* This is only supported for:
|
||||
* - VulkanPlatform
|
||||
* When the following device extensions are available:
|
||||
* - VK_KHR_dynamic_rendering
|
||||
* - VK_EXT_vertex_input_dynamic_state
|
||||
* Should be enabled only for devices where it has been shown this is effective.
|
||||
*/
|
||||
bool vulkanEnableAsyncPipelineCachePrewarming = false;
|
||||
|
||||
/**
|
||||
* Bypass the staging buffer because the device is of Unified Memory Architecture.
|
||||
* This is only supported for:
|
||||
|
||||
@@ -50,7 +50,13 @@ public:
|
||||
descriptor_binding_t binding;
|
||||
};
|
||||
|
||||
struct DescriptorSetLayoutBinding {
|
||||
descriptor_set_t set;
|
||||
DescriptorSetLayout layout;
|
||||
};
|
||||
|
||||
using SpecializationConstant = std::variant<int32_t, float, bool>;
|
||||
using DescriptorSetLayoutArray = utils::FixedCapacityVector<DescriptorSetLayoutBinding>;
|
||||
|
||||
struct Uniform { // For ES2 support
|
||||
utils::CString name; // full qualified name of the uniform field
|
||||
@@ -147,6 +153,19 @@ public:
|
||||
return mDescriptorBindings;
|
||||
}
|
||||
|
||||
inline Program& descriptorLayout(backend::descriptor_set_t set,
|
||||
DescriptorSetLayout descriptorLayout) noexcept {
|
||||
mDescriptorLayouts.push_back({
|
||||
.set = set,
|
||||
.layout = std::move(descriptorLayout),
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
const DescriptorSetLayoutArray& getDescriptorSetLayouts() const noexcept {
|
||||
return mDescriptorLayouts;
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<PushConstant> const& getPushConstants(
|
||||
ShaderStage stage) const noexcept {
|
||||
return mPushConstants[static_cast<uint8_t>(stage)];
|
||||
@@ -176,6 +195,11 @@ private:
|
||||
std::array<utils::FixedCapacityVector<PushConstant>, SHADER_TYPE_COUNT> mPushConstants;
|
||||
DescriptorSetInfo mDescriptorBindings;
|
||||
|
||||
// Descriptions for descriptor set layouts that may be used for this Program, which
|
||||
// can be useful for attempting to compile the pipeline ahead of time.
|
||||
DescriptorSetLayoutArray mDescriptorLayouts =
|
||||
DescriptorSetLayoutArray::with_capacity(MAX_DESCRIPTOR_SET_COUNT);
|
||||
|
||||
// For ES2 support only
|
||||
AttributesInfo mAttributes;
|
||||
BindingUniformsInfo mBindingUniformsInfo;
|
||||
|
||||
@@ -64,7 +64,7 @@ protected:
|
||||
std::vector<int> mAttribs;
|
||||
|
||||
// For shared contexts
|
||||
static constexpr int SHARED_CONTEXT_NUM = 1;
|
||||
static constexpr int SHARED_CONTEXT_NUM = 2;
|
||||
std::vector<HGLRC> mAdditionalContexts;
|
||||
std::atomic<int> mNextFreeSharedContextIndex{0};
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@@ -55,14 +56,31 @@ struct VulkanCmdFence;
|
||||
*/
|
||||
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
|
||||
public:
|
||||
/**
|
||||
* Encapsulates information required to instantiate a known external format,
|
||||
* typically for the purpose of preloading a pipeline cache for materials using
|
||||
* external formats for samplers.
|
||||
*/
|
||||
struct ExternalYcbcrFormat {
|
||||
uint64_t externalFormat;
|
||||
VkSamplerYcbcrModelConversion ycbcrModelConversion;
|
||||
VkSamplerYcbcrRange ycbcrRange;
|
||||
};
|
||||
|
||||
struct ExtensionHashFn {
|
||||
std::size_t operator()(utils::CString const& s) const noexcept {
|
||||
return std::hash<std::string>{}(s.data());
|
||||
}
|
||||
};
|
||||
// Note: utils::CString::operator== has an edge case that breaks for the extension set.
|
||||
// Instead, we'll provide our own comparator.
|
||||
struct ExtensionEqualFn {
|
||||
bool operator()(utils::CString const& a, utils::CString const& b) const noexcept {
|
||||
return strcmp(a.c_str(), b.c_str()) == 0;
|
||||
}
|
||||
};
|
||||
// Utility for managing device or instance extensions during initialization.
|
||||
using ExtensionSet = std::unordered_set<utils::CString, ExtensionHashFn>;
|
||||
using ExtensionSet = std::unordered_set<utils::CString, ExtensionHashFn, ExtensionEqualFn>;
|
||||
|
||||
/**
|
||||
* A collection of handles to objects and metadata that comprises a Vulkan context. The client
|
||||
@@ -437,6 +455,50 @@ protected:
|
||||
std::shared_ptr<VulkanCmdFence> fenceStatus;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the VkInstance used by Filament's Vulkan backend.
|
||||
*
|
||||
* This method can be overridden in subclasses to customize VkInstance creation, such as
|
||||
* adding application-specific layers or extensions.
|
||||
*
|
||||
* The provided `createInfo` contains layers and extensions required by Filament.
|
||||
* If you override this method and need to modify the `createInfo` struct, you must first
|
||||
* make a copy of it and modify the copy.
|
||||
*
|
||||
* @param createInfo The VkInstanceCreateInfo prepared by Filament.
|
||||
* @return The created VkInstance, or VK_NULL_HANDLE on failure.
|
||||
*/
|
||||
virtual VkInstance createVkInstance(VkInstanceCreateInfo const& createInfo) noexcept;
|
||||
|
||||
/**
|
||||
* Selects a VkPhysicalDevice (GPU) for Filament's Vulkan backend to use.
|
||||
*
|
||||
* This method can be overridden in subclasses to implement custom GPU selection logic.
|
||||
* For example, an application might override this to prefer a discrete GPU over an
|
||||
* integrated one based on device properties.
|
||||
*
|
||||
* The default implementation selects the first device that meets Filament's requirements.
|
||||
*
|
||||
* @param instance The VkInstance to enumerate devices from.
|
||||
* @return The selected VkPhysicalDevice, or VK_NULL_HANDLE if no suitable device is found.
|
||||
*/
|
||||
virtual VkPhysicalDevice selectVkPhysicalDevice(VkInstance instance) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the VkDevice used by Filament's Vulkan backend.
|
||||
*
|
||||
* This method can be overridden in subclasses to customize VkDevice creation, such as
|
||||
* adding application-specific extensions or enabling features.
|
||||
*
|
||||
* The provided `createInfo` contains extensions and features required by Filament.
|
||||
* If you override this method and need to modify the `createInfo` struct, you must first
|
||||
* make a copy of it and modify the copy.
|
||||
*
|
||||
* @param createInfo The VkDeviceCreateInfo prepared by Filament.
|
||||
* @return The created VkDevice, or VK_NULL_HANDLE on failure.
|
||||
*/
|
||||
virtual VkDevice createVkDevice(VkDeviceCreateInfo const& createInfo) noexcept;
|
||||
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
virtual ExtensionSet getSwapchainInstanceExtensions() const = 0;
|
||||
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||
@@ -449,7 +511,48 @@ protected:
|
||||
*/
|
||||
bool isTransientAttachmentSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
void registerPipelineCachePrewarmExternalFormat(const ExternalYcbcrFormat& format) noexcept;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Contains information about features that should be requested
|
||||
* when calling vkCreateDevice, based on feature support from
|
||||
* vkGetPhysicalDeviceFeatures2.
|
||||
*/
|
||||
struct MiscDeviceFeatures {
|
||||
/**
|
||||
* This allows creation of a VkGraphicsPipeline without a
|
||||
* render pass specified.
|
||||
*/
|
||||
bool dynamicRendering;
|
||||
|
||||
/**
|
||||
* Allows creation of a 2d image view, or 2d image view array,
|
||||
* to be created from a 3d VkImage.
|
||||
*/
|
||||
bool imageView2Don3DImage;
|
||||
};
|
||||
|
||||
void createInstance(ExtensionSet const& requiredExts) noexcept;
|
||||
|
||||
void queryAndSetDeviceFeatures(Platform::DriverConfig const& driverConfig,
|
||||
ExtensionSet const& instExts, ExtensionSet const& deviceExts,
|
||||
void* sharedContext) noexcept;
|
||||
|
||||
void createLogicalDeviceAndQueues(ExtensionSet const& deviceExtensions,
|
||||
VkPhysicalDeviceFeatures const& features,
|
||||
VkPhysicalDeviceVulkan11Features const& vk11Features, bool createProtectedQueue,
|
||||
MiscDeviceFeatures const& requestedFeatures) noexcept;
|
||||
|
||||
friend struct VulkanPlatformPrivate;
|
||||
};
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
bool queryFrameTimestamps(SwapChain const* swapchain, uint64_t frameId,
|
||||
FrameTimestamps* outFrameTimestamps) const noexcept override;
|
||||
|
||||
|
||||
protected:
|
||||
ExtensionSet getSwapchainInstanceExtensions() const override;
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ public:
|
||||
// is where the driver can execute user callbacks.
|
||||
virtual void purge() noexcept = 0;
|
||||
|
||||
// Called from the engine thread (render-thread) to execute the `callback` via the `handler` if
|
||||
// it is available. Otherwise, if `handler` is null, the `callback` is executed on the main
|
||||
// thread via `purge()`.
|
||||
virtual void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) = 0;
|
||||
|
||||
virtual ShaderModel getShaderModel() const noexcept = 0;
|
||||
|
||||
// The shader languages used for shaders for this driver in order of preference, used to inform
|
||||
|
||||
@@ -74,8 +74,9 @@
|
||||
#define APPLY10(M, A, ...) EXPAND(M(A)), EXPAND(APPLY9(M, __VA_ARGS__))
|
||||
#define APPLY11(M, A, ...) EXPAND(M(A)), EXPAND(APPLY10(M, __VA_ARGS__))
|
||||
#define APPLY12(M, A, ...) EXPAND(M(A)), EXPAND(APPLY11(M, __VA_ARGS__))
|
||||
#define APPLY_N__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, X, ...) APPLY##X
|
||||
#define APPLY(M, ...) EXPAND(EXPAND(APPLY_N__(M, __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(M, __VA_ARGS__))
|
||||
#define APPLY13(M, A, ...) EXPAND(M(A)), EXPAND(APPLY12(M, __VA_ARGS__))
|
||||
#define APPLY_N__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, X, ...) APPLY##X
|
||||
#define APPLY(M, ...) EXPAND(EXPAND(APPLY_N__(M, __VA_ARGS__, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(M, __VA_ARGS__))
|
||||
|
||||
|
||||
#define PAIR_ARGS_0(M, ...)
|
||||
@@ -91,11 +92,12 @@
|
||||
#define PAIR_ARGS_10(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_9(M, __VA_ARGS__))
|
||||
#define PAIR_ARGS_11(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_10(M, __VA_ARGS__))
|
||||
#define PAIR_ARGS_12(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_11(M, __VA_ARGS__))
|
||||
#define PAIR_ARGS_13(M, X, Y, ...) M(X, Y), EXPAND(PAIR_ARGS_12(M, __VA_ARGS__))
|
||||
|
||||
#define PAIR_ARGS_N__(_0, E1, _1, E2, _2, E3, _3, E4, _4, E5, _5, E6, _6, E7, _7, E8, _8, E9, _9, E10, _10, E11, _11, E12, _12, X, ...) PAIR_ARGS_##X
|
||||
#define PAIR_ARGS_N__(_0, E1, _1, E2, _2, E3, _3, E4, _4, E5, _5, E6, _6, E7, _7, E8, _8, E9, _9, E10, _10, E11, _11, E12, _12, E13, _13, X, ...) PAIR_ARGS_##X
|
||||
|
||||
#define PAIR_ARGS_N(M, ...) \
|
||||
EXPAND(EXPAND(PAIR_ARGS_N__(0, ##__VA_ARGS__, 12, E, 11, E, 10, E, 9, E, 8, E, 7, E, 6, E, 5, E, 4, E, 3, E, 2, E, 1, E, 0))(M, __VA_ARGS__))
|
||||
EXPAND(EXPAND(PAIR_ARGS_N__(0, ##__VA_ARGS__, 13, E, 12, E, 11, E, 10, E, 9, E, 8, E, 7, E, 6, E, 5, E, 4, E, 3, E, 2, E, 1, E, 0))(M, __VA_ARGS__))
|
||||
|
||||
#define ARG(T, P) T P
|
||||
|
||||
@@ -192,11 +194,27 @@ DECL_DRIVER_API_TAGGED_R_N(backend::IndexBufferHandle, createIndexBuffer,
|
||||
uint32_t, indexCount,
|
||||
backend::BufferUsage, usage)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::IndexBufferHandle, createIndexBufferAsync,
|
||||
backend::ElementType, elementType,
|
||||
uint32_t, indexCount,
|
||||
backend::BufferUsage, usage,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::BufferObjectHandle, createBufferObject,
|
||||
uint32_t, byteCount,
|
||||
backend::BufferObjectBinding, bindingType,
|
||||
backend::BufferUsage, usage)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::BufferObjectHandle, createBufferObjectAsync,
|
||||
uint32_t, byteCount,
|
||||
backend::BufferObjectBinding, bindingType,
|
||||
backend::BufferUsage, usage,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
|
||||
backend::SamplerType, target,
|
||||
uint8_t, levels,
|
||||
@@ -207,6 +225,19 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
|
||||
uint32_t, depth,
|
||||
backend::TextureUsage, usage)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureAsync,
|
||||
backend::SamplerType, target,
|
||||
uint8_t, levels,
|
||||
backend::TextureFormat, format,
|
||||
uint8_t, samples,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
uint32_t, depth,
|
||||
backend::TextureUsage, usage,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureView,
|
||||
backend::TextureHandle, texture,
|
||||
uint8_t, baseLevel,
|
||||
@@ -219,6 +250,16 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureViewSwizzle,
|
||||
backend::TextureSwizzle, b,
|
||||
backend::TextureSwizzle, a)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureViewSwizzleAsync,
|
||||
backend::TextureHandle, texture,
|
||||
backend::TextureSwizzle, r,
|
||||
backend::TextureSwizzle, g,
|
||||
backend::TextureSwizzle, b,
|
||||
backend::TextureSwizzle, a,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage2,
|
||||
backend::SamplerType, target,
|
||||
backend::TextureFormat, format,
|
||||
@@ -254,6 +295,20 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTexture,
|
||||
uint32_t, depth,
|
||||
backend::TextureUsage, usage)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTextureAsync,
|
||||
intptr_t, id,
|
||||
backend::SamplerType, target,
|
||||
uint8_t, levels,
|
||||
backend::TextureFormat, format,
|
||||
uint8_t, samples,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
uint32_t, depth,
|
||||
backend::TextureUsage, usage,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_TAGGED_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
|
||||
backend::VertexBufferHandle, vbh,
|
||||
backend::IndexBufferHandle, ibh,
|
||||
@@ -357,6 +412,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isAsynchronousModeEnabled)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(size_t, getMaxTextureSize, backend::SamplerType, target)
|
||||
@@ -382,16 +438,40 @@ DECL_DRIVER_API_N(setVertexBufferObject,
|
||||
uint32_t, index,
|
||||
backend::BufferObjectHandle, bufferObject)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::AsyncCallId, setVertexBufferObjectAsync,
|
||||
backend::VertexBufferHandle, vbh,
|
||||
uint32_t, index,
|
||||
backend::BufferObjectHandle, bufferObject,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(updateIndexBuffer,
|
||||
backend::IndexBufferHandle, ibh,
|
||||
backend::BufferDescriptor&&, data,
|
||||
uint32_t, byteOffset)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::AsyncCallId, updateIndexBufferAsync,
|
||||
backend::IndexBufferHandle, ibh,
|
||||
backend::BufferDescriptor&&, data,
|
||||
uint32_t, byteOffset,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(updateBufferObject,
|
||||
backend::BufferObjectHandle, ibh,
|
||||
backend::BufferDescriptor&&, data,
|
||||
uint32_t, byteOffset)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::AsyncCallId, updateBufferObjectAsync,
|
||||
backend::BufferObjectHandle, ibh,
|
||||
backend::BufferDescriptor&&, data,
|
||||
uint32_t, byteOffset,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(updateBufferObjectUnsynchronized,
|
||||
backend::BufferObjectHandle, boh,
|
||||
backend::BufferDescriptor&&, data,
|
||||
@@ -411,6 +491,20 @@ DECL_DRIVER_API_N(update3DImage,
|
||||
uint32_t, depth,
|
||||
backend::PixelBufferDescriptor&&, data)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::AsyncCallId, update3DImageAsync,
|
||||
backend::TextureHandle, th,
|
||||
uint32_t, level,
|
||||
uint32_t, xoffset,
|
||||
uint32_t, yoffset,
|
||||
uint32_t, zoffset,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
uint32_t, depth,
|
||||
backend::PixelBufferDescriptor&&, data,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(generateMipmaps,
|
||||
backend::TextureHandle, th)
|
||||
|
||||
@@ -577,6 +671,19 @@ DECL_DRIVER_API_N(dispatchCompute,
|
||||
DECL_DRIVER_API_N(scissor,
|
||||
Viewport, scissor)
|
||||
|
||||
/*
|
||||
* Asyncronous operation helpers
|
||||
* --------------------
|
||||
*/
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::AsyncCallId, queueCommandAsync,
|
||||
utils::Invocable<void(void)>&&, command,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, cancelAsyncJob, backend::AsyncCallId, jobId)
|
||||
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <math/half.h>
|
||||
#include <math/vec2.h>
|
||||
@@ -47,45 +49,41 @@ using namespace filament::math;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
DriverBase::DriverBase() noexcept {
|
||||
if constexpr (UTILS_HAS_THREADING) {
|
||||
// This thread services user callbacks
|
||||
mServiceThread = std::thread([this]() {
|
||||
do {
|
||||
auto& serviceThreadCondition = mServiceThreadCondition;
|
||||
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
|
||||
DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mDriverConfig(driverConfig) {
|
||||
#if UTILS_HAS_THREADING
|
||||
// This thread services user callbacks
|
||||
mServiceThread = std::thread([this]() {
|
||||
JobSystem::setThreadName("ServiceThread");
|
||||
do {
|
||||
auto& serviceThreadCondition = mServiceThreadCondition;
|
||||
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
|
||||
|
||||
// wait for some callbacks to dispatch
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
|
||||
serviceThreadCondition.wait(lock);
|
||||
}
|
||||
if (mExitRequested) {
|
||||
break;
|
||||
}
|
||||
// move the callbacks to a temporary vector
|
||||
auto callbacks(std::move(serviceThreadCallbackQueue));
|
||||
lock.unlock();
|
||||
// and make sure to call them without our lock held
|
||||
for (auto[handler, callback, user]: callbacks) {
|
||||
handler->post(user, callback);
|
||||
}
|
||||
} while (true);
|
||||
});
|
||||
}
|
||||
// wait for some callbacks to dispatch
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
|
||||
serviceThreadCondition.wait(lock);
|
||||
}
|
||||
if (mExitRequested) {
|
||||
break;
|
||||
}
|
||||
// move the callbacks to a temporary vector
|
||||
auto callbacks(std::move(serviceThreadCallbackQueue));
|
||||
lock.unlock();
|
||||
// and make sure to call them without our lock held
|
||||
for (auto[handler, callback, user]: callbacks) {
|
||||
handler->post(user, callback);
|
||||
}
|
||||
} while (true);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
DriverBase::~DriverBase() noexcept {
|
||||
assert_invariant(mCallbacks.empty());
|
||||
assert_invariant(mServiceThreadCallbackQueue.empty());
|
||||
if constexpr (UTILS_HAS_THREADING) {
|
||||
// quit our service thread
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
mExitRequested = true;
|
||||
mServiceThreadCondition.notify_one();
|
||||
lock.unlock();
|
||||
mServiceThread.join();
|
||||
}
|
||||
#if UTILS_HAS_THREADING
|
||||
stopServiceThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -109,11 +107,14 @@ void DriverBase::CallbackData::release(CallbackData* data) {
|
||||
|
||||
|
||||
void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
|
||||
if (handler && UTILS_HAS_THREADING) {
|
||||
#if UTILS_HAS_THREADING
|
||||
if (handler) {
|
||||
std::lock_guard<std::mutex> const lock(mServiceThreadLock);
|
||||
mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
|
||||
mServiceThreadCondition.notify_one();
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock(mPurgeLock);
|
||||
mCallbacks.emplace_back(user, callback);
|
||||
}
|
||||
@@ -181,6 +182,22 @@ void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
|
||||
}
|
||||
}
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
void DriverBase::stopServiceThread() noexcept {
|
||||
if (!mServiceThread.joinable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mServiceThreadLock);
|
||||
mExitRequested = true;
|
||||
}
|
||||
mServiceThreadCondition.notify_one();
|
||||
mServiceThread.join();
|
||||
assert_invariant(mServiceThreadCallbackQueue.empty());
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t Driver::getElementTypeSize(ElementType type) noexcept {
|
||||
switch (type) {
|
||||
case ElementType::BYTE: return sizeof(int8_t);
|
||||
|
||||
@@ -72,22 +72,24 @@ struct HwVertexBuffer : public HwBase {
|
||||
};
|
||||
|
||||
struct HwBufferObject : public HwBase {
|
||||
uint32_t byteCount{};
|
||||
uint32_t byteCount : 31;
|
||||
uint32_t asynchronous : 1;
|
||||
|
||||
HwBufferObject() noexcept = default;
|
||||
explicit HwBufferObject(uint32_t byteCount) noexcept : byteCount(byteCount) {}
|
||||
explicit HwBufferObject(uint32_t byteCount, bool async) noexcept : byteCount(byteCount), asynchronous(async) {}
|
||||
};
|
||||
|
||||
struct HwMemoryMappedBuffer : public HwBase {
|
||||
};
|
||||
|
||||
struct HwIndexBuffer : public HwBase {
|
||||
uint32_t count : 27;
|
||||
uint32_t count : 26; // 67M indices
|
||||
uint32_t elementSize : 5;
|
||||
uint32_t asynchronous : 1;
|
||||
|
||||
HwIndexBuffer() noexcept : count{}, elementSize{} { }
|
||||
HwIndexBuffer(uint8_t elementSize, uint32_t indexCount) noexcept :
|
||||
count(indexCount), elementSize(elementSize) {
|
||||
HwIndexBuffer(uint8_t elementSize, uint32_t indexCount, bool async) noexcept :
|
||||
count(indexCount), elementSize(elementSize), asynchronous(async) {
|
||||
// we could almost store elementSize on 4 bits because it's never > 16 and never 0
|
||||
assert_invariant(elementSize > 0 && elementSize <= 16);
|
||||
assert_invariant(indexCount < (1u << 27));
|
||||
@@ -120,16 +122,19 @@ struct HwTexture : public HwBase {
|
||||
uint8_t levels : 4; // This allows up to 15 levels (max texture size of 32768 x 32768)
|
||||
uint8_t samples : 4; // Sample count per pixel (should always be a power of 2)
|
||||
TextureFormat format{};
|
||||
uint8_t reserved0 = 0;
|
||||
struct {
|
||||
uint8_t asynchronous : 1;
|
||||
uint8_t reserved : 7;
|
||||
};
|
||||
TextureUsage usage{};
|
||||
uint16_t reserved1 = 0;
|
||||
HwStream* hwStream = nullptr;
|
||||
|
||||
HwTexture() noexcept : levels{}, samples{} {}
|
||||
HwTexture(backend::SamplerType target, uint8_t levels, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureFormat fmt, TextureUsage usage) noexcept
|
||||
: width(width), height(height), depth(depth),
|
||||
target(target), levels(levels), samples(samples), format(fmt), usage(usage) { }
|
||||
HwTexture(backend::SamplerType target, uint8_t levels, uint8_t samples, uint32_t width,
|
||||
uint32_t height, uint32_t depth, TextureFormat fmt, TextureUsage usage, bool async) noexcept
|
||||
: width(width), height(height), depth(depth), target(target), levels(levels),
|
||||
samples(samples), format(fmt), asynchronous(async), usage(usage) {}
|
||||
};
|
||||
|
||||
struct HwRenderTarget : public HwBase {
|
||||
@@ -168,11 +173,13 @@ struct HwTimerQuery : public HwBase {
|
||||
|
||||
/*
|
||||
* Base class of all Driver implementations
|
||||
* If multithreading is supported, this class creates a `ServiceThread` responsible for executing
|
||||
* user handlers.
|
||||
*/
|
||||
|
||||
class DriverBase : public Driver {
|
||||
public:
|
||||
DriverBase() noexcept;
|
||||
explicit DriverBase(const Platform::DriverConfig& driverConfig) noexcept;
|
||||
~DriverBase() noexcept override;
|
||||
|
||||
void purge() noexcept final;
|
||||
@@ -205,7 +212,7 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback);
|
||||
void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) final;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Privates
|
||||
@@ -214,6 +221,10 @@ public:
|
||||
protected:
|
||||
class CallbackDataDetails;
|
||||
|
||||
Platform::DriverConfig const& getDriverConfig() const noexcept {
|
||||
return mDriverConfig;
|
||||
}
|
||||
|
||||
void scheduleDestroy(BufferDescriptor&& buffer) {
|
||||
if (buffer.hasCallback()) {
|
||||
scheduleDestroySlow(std::move(buffer));
|
||||
@@ -227,15 +238,25 @@ protected:
|
||||
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
// Stops the `ServiceThread`. This method is called during destruction but may be called
|
||||
// explicitly if earlier shutdown is needed. This method is idempotent.
|
||||
void stopServiceThread() noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
const Platform::DriverConfig mDriverConfig;
|
||||
|
||||
std::mutex mPurgeLock;
|
||||
std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
std::thread mServiceThread;
|
||||
std::mutex mServiceThreadLock;
|
||||
std::condition_variable mServiceThreadCondition;
|
||||
std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue;
|
||||
bool mExitRequested = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ void Platform::debugUpdateStat(const char* key, uint64_t intValue) {
|
||||
callback = mDebugUpdateStat;
|
||||
}
|
||||
if (callback) {
|
||||
(*callback)(key, intValue, "");
|
||||
(*callback)(key, intValue, utils::CString(""));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ private:
|
||||
const std::function<void(const BufferState&, MetalBuffer*, uint32_t)>& f);
|
||||
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
backend::AsynchronousMode const mAsynchronousMode;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
@@ -111,14 +111,16 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
|
||||
|
||||
MetalDriver::MetalDriver(
|
||||
PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mPlatform(*platform),
|
||||
: DriverBase(driverConfig),
|
||||
mPlatform(*platform),
|
||||
mContext(new MetalContext),
|
||||
mHandleAllocator(
|
||||
"Handles",
|
||||
driverConfig.handleArenaSize,
|
||||
driverConfig.disableHandleUseAfterFreeCheck,
|
||||
driverConfig.disableHeapHandleTags),
|
||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||
mStereoscopicType(driverConfig.stereoscopicType),
|
||||
mAsynchronousMode(driverConfig.asynchronousMode) {
|
||||
mContext->driver = this;
|
||||
|
||||
TrackedMetalBuffer::setPlatform(platform);
|
||||
@@ -461,6 +463,12 @@ void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elem
|
||||
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createIndexBufferAsyncR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
uint32_t indexCount, BufferUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
auto* bufferObject =
|
||||
@@ -472,6 +480,12 @@ void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteC
|
||||
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
// fixme: TextureUsage is a bitfield
|
||||
inline const char* stringify(TextureUsage usage) {
|
||||
switch (usage) {
|
||||
@@ -523,6 +537,13 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
uint32_t depth, TextureUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
|
||||
MetalTexture const* src = handle_cast<MetalTexture>(srch);
|
||||
@@ -543,6 +564,13 @@ void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTextu
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||
backend::SamplerType target,
|
||||
backend::TextureFormat format,
|
||||
@@ -602,6 +630,14 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t i,
|
||||
SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
uint32_t depth, TextureUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType pt, utils::ImmutableCString&& tag) {
|
||||
@@ -794,14 +830,26 @@ Handle<HwIndexBuffer> MetalDriver::createIndexBufferS() noexcept {
|
||||
return alloc_handle<MetalIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwIndexBuffer> MetalDriver::createIndexBufferAsyncS() noexcept {
|
||||
return alloc_handle<MetalIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> MetalDriver::createBufferObjectS() noexcept {
|
||||
return alloc_handle<MetalBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> MetalDriver::createBufferObjectAsyncS() noexcept {
|
||||
return alloc_handle<MetalBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::createTextureS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::createTextureAsyncS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::createTextureViewS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
@@ -810,6 +858,10 @@ Handle<HwTexture> MetalDriver::createTextureViewSwizzleS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::createTextureViewSwizzleAsyncS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::createTextureExternalImage2S() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
@@ -826,6 +878,30 @@ Handle<HwTexture> MetalDriver::importTextureS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> MetalDriver::importTextureAsyncS() noexcept {
|
||||
return alloc_handle<MetalTexture>();
|
||||
}
|
||||
|
||||
AsyncCallId MetalDriver::update3DImageAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId MetalDriver::setVertexBufferObjectAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId MetalDriver::updateBufferObjectAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId MetalDriver::updateIndexBufferAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
Handle<HwRenderPrimitive> MetalDriver::createRenderPrimitiveS() noexcept {
|
||||
return alloc_handle<MetalRenderPrimitive>();
|
||||
}
|
||||
@@ -874,6 +950,11 @@ Handle<HwDescriptorSet> MetalDriver::createDescriptorSetS() noexcept {
|
||||
return alloc_handle<MetalDescriptorSet>();
|
||||
}
|
||||
|
||||
AsyncCallId MetalDriver::queueCommandAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
void MetalDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
||||
if (vbih) {
|
||||
destruct_handle<MetalVertexBufferInfo>(vbih);
|
||||
@@ -1216,6 +1297,10 @@ bool MetalDriver::isDepthClampSupported() {
|
||||
return mContext->supportsDepthClamp;
|
||||
}
|
||||
|
||||
bool MetalDriver::isAsynchronousModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
switch (workaround) {
|
||||
case Workaround::SPLIT_EASU:
|
||||
@@ -1291,6 +1376,12 @@ void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&
|
||||
[&]() { return mHandleAllocator.getHandleTag(ibh.getId()).c_str_safe(); });
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
void MetalDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
|
||||
BufferDescriptor&& data, uint32_t byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
|
||||
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
|
||||
uint32_t byteOffset) {
|
||||
@@ -1307,6 +1398,12 @@ void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescripto
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
|
||||
void MetalDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
|
||||
BufferDescriptor&& data, uint32_t byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
|
||||
BufferDescriptor&& data, uint32_t byteOffset) {
|
||||
auto* bo = handle_cast<MetalBufferObject>(boh);
|
||||
@@ -1332,6 +1429,12 @@ void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t ind
|
||||
vertexBuffer->buffers[index] = bufferObject->getBuffer();
|
||||
}
|
||||
|
||||
void MetalDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
|
||||
uint32_t index, Handle<HwBufferObject> boh, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
@@ -1348,6 +1451,14 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
||||
th.getId(), level, xoffset, yoffset, zoffset, width, height, depth);
|
||||
}
|
||||
|
||||
void MetalDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
|
||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
PixelBufferDescriptor&& data, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void MetalDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
|
||||
// FIXME: implement setupExternalImage2
|
||||
}
|
||||
@@ -2300,6 +2411,16 @@ void MetalDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t
|
||||
mmb->copy(*this, offset, std::move(data));
|
||||
}
|
||||
|
||||
void MetalDriver::queueCommandAsyncR(AsyncCallId jobId, utils::Invocable<void()>&& command,
|
||||
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
bool MetalDriver::cancelAsyncJob(AsyncCallId jobId) {
|
||||
// TODO: implement this.
|
||||
return false;
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
template class ConcreteDispatcher<MetalDriver>;
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ class MetalDescriptorSetLayout : public HwDescriptorSetLayout {
|
||||
public:
|
||||
MetalDescriptorSetLayout(DescriptorSetLayout&& layout) noexcept;
|
||||
|
||||
const auto& getBindings() const noexcept { return mLayout.bindings; }
|
||||
const auto& getBindings() const noexcept { return mLayout.descriptors; }
|
||||
|
||||
size_t getDynamicOffsetCount() const noexcept { return mDynamicOffsetCount; }
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ MetalAttachment MetalSwapChain::acquireBaseDrawable() {
|
||||
|
||||
MetalBufferObject::MetalBufferObject(MetalContext& context, BufferObjectBinding bindingType,
|
||||
BufferUsage usage, uint32_t byteCount)
|
||||
: HwBufferObject(byteCount), buffer(context, bindingType, usage, byteCount) {}
|
||||
: HwBufferObject(byteCount, false), buffer(context, bindingType, usage, byteCount) {}
|
||||
|
||||
void MetalBufferObject::updateBuffer(
|
||||
void* data, size_t size, uint32_t byteOffset, TagResolver&& getHandleTag) {
|
||||
@@ -635,7 +635,7 @@ MetalVertexBuffer::MetalVertexBuffer(MetalContext& context,
|
||||
}
|
||||
|
||||
MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, BufferUsage usage, uint8_t elementSize,
|
||||
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
|
||||
uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount, false),
|
||||
buffer(context, BufferObjectBinding::VERTEX, usage, elementSize * indexCount, true) { }
|
||||
|
||||
MetalProgram::MetalProgram(MetalContext& context, Program&& program) noexcept
|
||||
@@ -664,7 +664,7 @@ void MetalProgram::initialize() {
|
||||
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage) noexcept
|
||||
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context) {
|
||||
: HwTexture(target, levels, samples, width, height, depth, format, usage, false), context(context) {
|
||||
assert_invariant(target != SamplerType::SAMPLER_EXTERNAL);
|
||||
|
||||
devicePixelFormat = decidePixelFormat(&context, format);
|
||||
@@ -756,7 +756,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
|
||||
MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, uint8_t baseLevel,
|
||||
uint8_t levelCount) noexcept
|
||||
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
||||
src->format, src->usage),
|
||||
src->format, src->usage, false),
|
||||
context(context),
|
||||
devicePixelFormat(src->devicePixelFormat),
|
||||
externalImage(src->externalImage) {
|
||||
@@ -767,7 +767,7 @@ MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, uint8
|
||||
MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, TextureSwizzle r,
|
||||
TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) noexcept
|
||||
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
||||
src->format, src->usage),
|
||||
src->format, src->usage, false),
|
||||
context(context),
|
||||
devicePixelFormat(src->devicePixelFormat),
|
||||
externalImage(src->externalImage) {
|
||||
@@ -786,13 +786,13 @@ MetalTexture::MetalTexture(MetalContext& context, MetalTexture const* src, Textu
|
||||
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format,
|
||||
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
id<MTLTexture> metalTexture) noexcept
|
||||
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context) {
|
||||
: HwTexture(target, levels, samples, width, height, depth, format, usage, false), context(context) {
|
||||
texture = metalTexture;
|
||||
}
|
||||
|
||||
MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t width,
|
||||
uint32_t height, TextureUsage usage, CVPixelBufferRef image) noexcept
|
||||
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage),
|
||||
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage, false),
|
||||
context(context),
|
||||
externalImage(std::make_shared<MetalExternalImage>(
|
||||
MetalExternalImage::createFromImage(context, image))) {
|
||||
@@ -801,7 +801,7 @@ MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t
|
||||
|
||||
MetalTexture::MetalTexture(MetalContext& context, TextureFormat format, uint32_t width,
|
||||
uint32_t height, TextureUsage usage, CVPixelBufferRef image, uint32_t plane) noexcept
|
||||
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage),
|
||||
: HwTexture(SamplerType::SAMPLER_EXTERNAL, 1, 1, width, height, 1, format, usage, false),
|
||||
context(context),
|
||||
externalImage(std::make_shared<MetalExternalImage>(
|
||||
MetalExternalImage::createFromImagePlane(context, image, plane))) {
|
||||
@@ -1441,7 +1441,7 @@ void MetalFence::cancel() {
|
||||
MetalDescriptorSetLayout::MetalDescriptorSetLayout(DescriptorSetLayout&& l) noexcept
|
||||
: mLayout(std::move(l)) {
|
||||
size_t dynamicBindings = 0;
|
||||
for (const auto& binding : mLayout.bindings) {
|
||||
for (const auto& binding : mLayout.descriptors) {
|
||||
if (any(binding.flags & DescriptorFlags::DYNAMIC_OFFSET)) {
|
||||
dynamicBindings++;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,13 @@
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* NoopDriver::create() {
|
||||
return new NoopDriver();
|
||||
Platform::DriverConfig driverConfig;
|
||||
return new NoopDriver(driverConfig);
|
||||
}
|
||||
|
||||
NoopDriver::NoopDriver() noexcept = default;
|
||||
NoopDriver::NoopDriver(const Platform::DriverConfig& driverConfig) noexcept
|
||||
: DriverBase(driverConfig) {
|
||||
}
|
||||
|
||||
NoopDriver::~NoopDriver() noexcept = default;
|
||||
|
||||
@@ -247,6 +250,10 @@ bool NoopDriver::isDepthClampSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NoopDriver::isAsynchronousModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NoopDriver::isWorkaroundNeeded(Workaround) {
|
||||
return false;
|
||||
}
|
||||
@@ -465,4 +472,8 @@ bool NoopDriver::queryFrameTimestamps(SwapChainHandle swapChain, uint64_t frameI
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NoopDriver::cancelAsyncJob(AsyncCallId jobId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
namespace filament::backend {
|
||||
|
||||
class NoopDriver final : public DriverBase {
|
||||
NoopDriver() noexcept;
|
||||
NoopDriver(const Platform::DriverConfig& driverConfig) noexcept;
|
||||
~NoopDriver() noexcept override;
|
||||
Dispatcher getDispatcher() const noexcept final;
|
||||
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
|
||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||
RetType methodName##S() noexcept override { \
|
||||
return RetType((RetType::HandleId)nextFakeHandle++); } \
|
||||
return RetType(nextFakeHandle++); } \
|
||||
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl) { }
|
||||
|
||||
#include "private/backend/DriverAPI.inc"
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
|
||||
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
|
||||
mStorage[set][binding] = { uint8_t(entry.binding),
|
||||
DescriptorSetLayoutBinding::isSampler(entry.type) };
|
||||
DescriptorSetLayoutDescriptor::isSampler(entry.type) };
|
||||
mActiveDescriptors[set].set(binding);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace filament::backend {
|
||||
struct GLBufferObject : public HwBufferObject {
|
||||
using HwBufferObject::HwBufferObject;
|
||||
GLBufferObject(uint32_t size,
|
||||
BufferObjectBinding bindingType, BufferUsage usage) noexcept
|
||||
: HwBufferObject(size), usage(usage), bindingType(bindingType) {
|
||||
BufferObjectBinding bindingType, BufferUsage usage, bool async) noexcept
|
||||
: HwBufferObject(size, async), usage(usage), bindingType(bindingType) {
|
||||
}
|
||||
|
||||
struct {
|
||||
|
||||
@@ -56,7 +56,7 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
|
||||
|
||||
// We have allocated enough storage for all descriptors. Now allocate the empty descriptor
|
||||
// themselves.
|
||||
for (auto const& entry : layout->bindings) {
|
||||
for (auto const& entry : layout->descriptors) {
|
||||
size_t const index = entry.binding;
|
||||
|
||||
// now we'll initialize the alternative for each way we can handle this descriptor.
|
||||
@@ -372,10 +372,10 @@ void GLDescriptorSet::validate(HandleAllocatorGL& allocator,
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE
|
||||
bool const pipelineLayoutMatchesDescriptorSetLayout = std::equal(
|
||||
dsl->bindings.begin(), dsl->bindings.end(),
|
||||
cur->bindings.begin(),
|
||||
[](DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) {
|
||||
dsl->descriptors.begin(), dsl->descriptors.end(),
|
||||
cur->descriptors.begin(),
|
||||
[](DescriptorSetLayoutDescriptor const& lhs,
|
||||
DescriptorSetLayoutDescriptor const& rhs) {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.stageFlags == rhs.stageFlags &&
|
||||
lhs.binding == rhs.binding &&
|
||||
|
||||
@@ -33,12 +33,12 @@ struct GLDescriptorSetLayout : public HwDescriptorSetLayout, public DescriptorSe
|
||||
explicit GLDescriptorSetLayout(DescriptorSetLayout&& layout) noexcept
|
||||
: DescriptorSetLayout(std::move(layout)) {
|
||||
|
||||
std::sort(bindings.begin(), bindings.end(),
|
||||
std::sort(descriptors.begin(), descriptors.end(),
|
||||
[](auto&& lhs, auto&& rhs){
|
||||
return lhs.binding < rhs.binding;
|
||||
});
|
||||
|
||||
auto p = std::max_element(bindings.cbegin(), bindings.cend(),
|
||||
auto p = std::max_element(descriptors.cbegin(), descriptors.cend(),
|
||||
[](auto const& lhs, auto const& rhs) {
|
||||
return lhs.binding < rhs.binding;
|
||||
});
|
||||
|
||||
@@ -373,8 +373,8 @@ public:
|
||||
|
||||
FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; }
|
||||
|
||||
// This is the index of the context in use. Must be 0 or 1. This is used to manange the
|
||||
// OpenGL name of ContainerObjects within each context.
|
||||
// This is the index of the context in use. Must be either 0 (Unprotected) or 1 (Protected).
|
||||
// This is used to manage the OpenGL name of ContainerObjects within each context.
|
||||
uint32_t contextIndex = 0;
|
||||
|
||||
// Try to keep the State structure sorted by data-access patterns
|
||||
@@ -536,7 +536,7 @@ private:
|
||||
TimerQueryFactoryInterface* mTimerQueryFactory = nullptr;
|
||||
std::vector<std::function<void(OpenGLContext&)>> mDestroyWithNormalContext;
|
||||
RenderPrimitive mDefaultVAO;
|
||||
std::optional<GLuint> mDefaultFbo[2];
|
||||
std::optional<GLuint> mDefaultFbo[2]; // 0:Unprotected, 1:Protected
|
||||
mutable tsl::robin_map<SamplerParams, GLuint,
|
||||
SamplerParams::Hasher, SamplerParams::EqualTo> mSamplerMap;
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#include "OpenGLDriver.h"
|
||||
|
||||
#include "CommandStreamDispatcher.h"
|
||||
#include "GLTexture.h"
|
||||
#include "GLMemoryMappedBuffer.h"
|
||||
#include "GLTexture.h"
|
||||
#include "GLUtils.h"
|
||||
#include "OpenGLContext.h"
|
||||
#include "OpenGLDriverFactory.h"
|
||||
@@ -126,6 +126,7 @@
|
||||
|
||||
#if DEBUG_MARKER_LEVEL == DEBUG_MARKER_PROFILE
|
||||
# define DEBUG_MARKER()
|
||||
# define DEBUG_MARKER_NAME(name)
|
||||
# define PROFILE_MARKER(marker) PROFILE_SCOPE(marker);
|
||||
# if DEBUG_GROUP_MARKER_LEVEL != DEBUG_GROUP_MARKER_NONE
|
||||
# error PROFILING is exclusive; group markers must be disabled.
|
||||
@@ -135,12 +136,14 @@
|
||||
# endif
|
||||
#elif DEBUG_MARKER_LEVEL > DEBUG_MARKER_NONE
|
||||
# define DEBUG_MARKER() DebugMarker _debug_marker(*this, __func__);
|
||||
# define DEBUG_MARKER_NAME(name) DebugMarker _debug_marker(*this, name);
|
||||
# define PROFILE_MARKER(marker) DEBUG_MARKER()
|
||||
# if DEBUG_MARKER_LEVEL & DEBUG_MARKER_PROFILE
|
||||
# error PROFILING is exclusive; all other debug features must be disabled.
|
||||
# endif
|
||||
#else
|
||||
# define DEBUG_MARKER()
|
||||
# define DEBUG_MARKER_NAME(name)
|
||||
# define PROFILE_MARKER(marker)
|
||||
#endif
|
||||
|
||||
@@ -286,14 +289,14 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mPlatform(*platform),
|
||||
: OpenGLDriverBase(driverConfig),
|
||||
mPlatform(*platform),
|
||||
mContext(mPlatform, driverConfig),
|
||||
mShaderCompilerService(*this),
|
||||
mHandleAllocator("Handles",
|
||||
driverConfig.handleArenaSize,
|
||||
driverConfig.disableHandleUseAfterFreeCheck,
|
||||
driverConfig.disableHeapHandleTags),
|
||||
mDriverConfig(driverConfig),
|
||||
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
|
||||
// set a reasonable default value for our stream array
|
||||
mTexturesWithStreamsAttached.reserve(8);
|
||||
@@ -312,6 +315,26 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
|
||||
#endif
|
||||
|
||||
mShaderCompilerService.init();
|
||||
|
||||
if (driverConfig.asynchronousMode != AsynchronousMode::NONE) {
|
||||
mJobQueue = JobQueue::create();
|
||||
|
||||
bool const useThreadWorker =
|
||||
(driverConfig.asynchronousMode == AsynchronousMode::THREAD_PREFERRED) &&
|
||||
UTILS_HAS_THREADING;
|
||||
|
||||
if (useThreadWorker) {
|
||||
ThreadWorker::Config threadWorkerConfig{
|
||||
"JobQueueThreadWorker",
|
||||
JobSystem::Priority::NORMAL,
|
||||
[this]() { mPlatform.createContext(true); },
|
||||
[this]() { mPlatform.releaseContext(); },
|
||||
};
|
||||
mJobWorker = ThreadWorker::create(mJobQueue, std::move(threadWorkerConfig));
|
||||
} else {
|
||||
mJobWorker = AmortizationWorker::create(mJobQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLDriver::~OpenGLDriver() noexcept { // NOLINT(modernize-use-equals-default)
|
||||
@@ -359,8 +382,19 @@ void OpenGLDriver::terminate() {
|
||||
delete mCurrentPushConstants;
|
||||
mCurrentPushConstants = nullptr;
|
||||
|
||||
mContext.terminate();
|
||||
// Flush all pending asynchronous tasks. Some tasks may end up posting follow-up operations to
|
||||
// the `ServiceThread` (e.g., via CountdownCallbackHandler or any user-provided handlers). So we
|
||||
// early stop the ServiceThread to ensure these are processed as well. Tasks posted to the main
|
||||
// thread (due to no user handler) during this process are handled later by `Driver::purge`
|
||||
// within `FEngine::shutdown`.
|
||||
if (getJobWorker()) {
|
||||
getJobWorker()->terminate();
|
||||
}
|
||||
#if UTILS_HAS_THREADING
|
||||
stopServiceThread();
|
||||
#endif
|
||||
|
||||
mContext.terminate();
|
||||
mPlatform.terminate();
|
||||
}
|
||||
|
||||
@@ -412,7 +446,8 @@ void OpenGLDriver::setPushConstant(ShaderStage const stage, uint8_t const index,
|
||||
if (std::holds_alternative<bool>(value)) {
|
||||
assert_invariant(type == ConstantType::BOOL);
|
||||
bool const bval = std::get<bool>(value);
|
||||
glUniform1i(location, bval ? 1 : 0);
|
||||
// This must be the 'ui' version of glUniform1 due to a crash on M-series macbooks.
|
||||
glUniform1ui(location, bval ? 1 : 0);
|
||||
} else if (std::holds_alternative<float>(value)) {
|
||||
assert_invariant(type == ConstantType::FLOAT);
|
||||
float const fval = std::get<float>(value);
|
||||
@@ -576,10 +611,18 @@ Handle<HwIndexBuffer> OpenGLDriver::createIndexBufferS() noexcept {
|
||||
return initHandle<GLIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwIndexBuffer> OpenGLDriver::createIndexBufferAsyncS() noexcept {
|
||||
return initHandle<GLIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> OpenGLDriver::createBufferObjectS() noexcept {
|
||||
return initHandle<GLBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> OpenGLDriver::createBufferObjectAsyncS() noexcept {
|
||||
return initHandle<GLBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwRenderPrimitive> OpenGLDriver::createRenderPrimitiveS() noexcept {
|
||||
return initHandle<GLRenderPrimitive>();
|
||||
}
|
||||
@@ -592,6 +635,10 @@ Handle<HwTexture> OpenGLDriver::createTextureS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> OpenGLDriver::createTextureAsyncS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> OpenGLDriver::createTextureViewS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
@@ -600,6 +647,10 @@ Handle<HwTexture> OpenGLDriver::createTextureViewSwizzleS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> OpenGLDriver::createTextureViewSwizzleAsyncS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> OpenGLDriver::createTextureExternalImage2S() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
@@ -616,6 +667,30 @@ Handle<HwTexture> OpenGLDriver::importTextureS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> OpenGLDriver::importTextureAsyncS() noexcept {
|
||||
return initHandle<GLTexture>();
|
||||
}
|
||||
|
||||
AsyncCallId OpenGLDriver::update3DImageAsyncS() noexcept {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->issueJobId();
|
||||
}
|
||||
|
||||
AsyncCallId OpenGLDriver::setVertexBufferObjectAsyncS() noexcept {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->issueJobId();
|
||||
}
|
||||
|
||||
AsyncCallId OpenGLDriver::updateBufferObjectAsyncS() noexcept {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->issueJobId();
|
||||
}
|
||||
|
||||
AsyncCallId OpenGLDriver::updateIndexBufferAsyncS() noexcept {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->issueJobId();
|
||||
}
|
||||
|
||||
Handle<HwRenderTarget> OpenGLDriver::createDefaultRenderTargetS() noexcept {
|
||||
return initHandle<GLRenderTarget>();
|
||||
}
|
||||
@@ -656,6 +731,11 @@ MemoryMappedBufferHandle OpenGLDriver::mapBufferS() noexcept {
|
||||
return initHandle<GLMemoryMappedBuffer>();
|
||||
}
|
||||
|
||||
AsyncCallId OpenGLDriver::queueCommandAsyncS() noexcept {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->issueJobId();
|
||||
}
|
||||
|
||||
void OpenGLDriver::createVertexBufferInfoR(
|
||||
Handle<HwVertexBufferInfo> vbih,
|
||||
uint8_t bufferCount,
|
||||
@@ -677,17 +757,11 @@ void OpenGLDriver::createVertexBufferR(
|
||||
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createIndexBufferR(
|
||||
Handle<HwIndexBuffer> ibh,
|
||||
ElementType const elementType,
|
||||
uint32_t indexCount,
|
||||
BufferUsage const usage,
|
||||
ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
void OpenGLDriver::createIndexBufferCommon(Handle<HwIndexBuffer> ibh, ElementType const elementType,
|
||||
uint32_t indexCount, BufferUsage const usage, utils::ImmutableCString&& tag) {
|
||||
auto& gl = mContext;
|
||||
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
|
||||
GLIndexBuffer* ib = construct<GLIndexBuffer>(ibh, elementSize, indexCount);
|
||||
GLIndexBuffer* ib = handle_cast<GLIndexBuffer*>(ibh);
|
||||
glGenBuffers(1, &ib->gl.buffer);
|
||||
GLsizeiptr const size = elementSize * GLsizeiptr(indexCount);
|
||||
gl.bindVertexArray(nullptr);
|
||||
@@ -697,9 +771,52 @@ void OpenGLDriver::createIndexBufferR(
|
||||
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, ImmutableCString&& tag) {
|
||||
void OpenGLDriver::createIndexBufferR(
|
||||
Handle<HwIndexBuffer> ibh,
|
||||
ElementType const elementType,
|
||||
uint32_t indexCount,
|
||||
BufferUsage const usage,
|
||||
ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLIndexBuffer>(ibh, elementSize, indexCount, false);
|
||||
|
||||
createIndexBufferCommon(ibh, elementType, indexCount, usage, std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createIndexBufferAsyncR(
|
||||
Handle<HwIndexBuffer> ibh,
|
||||
ElementType const elementType,
|
||||
uint32_t indexCount,
|
||||
BufferUsage const usage,
|
||||
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
|
||||
ImmutableCString&& tag) {
|
||||
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLIndexBuffer>(ibh, elementSize, indexCount, true);
|
||||
|
||||
assert_invariant(getJobQueue());
|
||||
|
||||
getJobQueue()->push([this, ibh, elementType, indexCount, usage, handler, callback, user,
|
||||
tag=std::move(tag)]() mutable {
|
||||
DEBUG_MARKER_NAME("createIndexBufferAsyncR")
|
||||
createIndexBufferCommon(ibh, elementType, indexCount, usage, std::move(tag));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::createBufferObjectCommon(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
assert_invariant(byteCount > 0);
|
||||
|
||||
auto& gl = mContext;
|
||||
@@ -707,7 +824,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
||||
gl.bindVertexArray(nullptr);
|
||||
}
|
||||
|
||||
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
|
||||
GLBufferObject* bo = handle_cast<GLBufferObject*>(boh);
|
||||
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
bo->gl.id = ++mLastAssignedEmulatedUboId;
|
||||
bo->gl.buffer = malloc(byteCount);
|
||||
@@ -723,6 +840,40 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
||||
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLBufferObject>(boh, byteCount, bindingType, usage, false);
|
||||
|
||||
createBufferObjectCommon(boh, byteCount, bindingType, usage, std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user, ImmutableCString&& tag) {
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLBufferObject>(boh, byteCount, bindingType, usage, true);
|
||||
|
||||
assert_invariant(getJobQueue());
|
||||
|
||||
getJobQueue()->push([this, boh, byteCount, bindingType, usage, handler, callback, user,
|
||||
tag=std::move(tag)]() mutable {
|
||||
DEBUG_MARKER_NAME("createBufferObjectAsyncR")
|
||||
createBufferObjectCommon(boh, byteCount, bindingType, usage, std::move(tag));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType const pt, ImmutableCString&& tag) {
|
||||
@@ -870,11 +1021,9 @@ void OpenGLDriver::textureStorage(GLTexture* t,
|
||||
t->depth = depth;
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
void OpenGLDriver::createTextureCommon(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLenum internalFormat = getInternalFormat(format);
|
||||
assert_invariant(internalFormat);
|
||||
|
||||
@@ -895,7 +1044,11 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
|
||||
auto const& gl = mContext;
|
||||
samples = std::clamp(samples, uint8_t(1u), uint8_t(gl.gets.max_samples));
|
||||
GLTexture* t = construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage);
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
|
||||
// Overwrite the updated `usage`.
|
||||
t->usage = usage;
|
||||
|
||||
if (UTILS_LIKELY(usage & TextureUsage::SAMPLEABLE)) {
|
||||
|
||||
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||
@@ -964,6 +1117,44 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, false);
|
||||
|
||||
createTextureCommon(th, target, levels, format, samples, width, height, depth, usage,
|
||||
std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback const callback,
|
||||
void* user, ImmutableCString&& tag) {
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, true);
|
||||
|
||||
assert_invariant(getJobQueue());
|
||||
|
||||
getJobQueue()->push([this, th, target, levels, format, samples, width, height, depth, usage,
|
||||
handler, callback, user, tag=std::move(tag)]() mutable {
|
||||
DEBUG_MARKER_NAME("createTextureAsyncR")
|
||||
createTextureCommon(th, target, levels, format, samples, width, height, depth, usage,
|
||||
std::move(tag));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
|
||||
Handle<HwTexture> srch, uint8_t const baseLevel, uint8_t const levelCount, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
@@ -986,7 +1177,8 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
|
||||
src->samples,
|
||||
src->width, src->height, src->depth,
|
||||
src->format,
|
||||
src->usage);
|
||||
src->usage,
|
||||
src->asynchronous);
|
||||
|
||||
t->gl = src->gl;
|
||||
t->gl.sidecarRenderBufferMS = 0;
|
||||
@@ -1011,11 +1203,9 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
|
||||
ImmutableCString&& tag) {
|
||||
|
||||
DEBUG_MARKER()
|
||||
void OpenGLDriver::createTextureViewSwizzleCommon(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b,
|
||||
TextureSwizzle const a, ImmutableCString&& tag) {
|
||||
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(any(src->usage & TextureUsage::SAMPLEABLE))
|
||||
@@ -1029,14 +1219,7 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
src->ref = initHandle<GLTextureRef>();
|
||||
}
|
||||
|
||||
GLTexture* t = construct<GLTexture>(th,
|
||||
src->target,
|
||||
src->levels,
|
||||
src->samples,
|
||||
src->width, src->height, src->depth,
|
||||
src->format,
|
||||
src->usage);
|
||||
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
t->gl = src->gl;
|
||||
t->gl.baseLevel = src->gl.baseLevel;
|
||||
t->gl.maxLevel = src->gl.maxLevel;
|
||||
@@ -1077,6 +1260,46 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
|
||||
ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
|
||||
construct<GLTexture>(th, src->target, src->levels, src->samples, src->width, src->height,
|
||||
src->depth, src->format, src->usage, src->asynchronous);
|
||||
|
||||
createTextureViewSwizzleCommon(th, srch, r, g, b, a, std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
|
||||
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
|
||||
ImmutableCString&& tag) {
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
|
||||
construct<GLTexture>(th, src->target, src->levels, src->samples, src->width, src->height,
|
||||
src->depth, src->format, src->usage, src->asynchronous);
|
||||
|
||||
assert_invariant(getJobQueue());
|
||||
|
||||
getJobQueue()->push([this, th, srch, r, g, b, a, handler, callback, user,
|
||||
tag=std::move(tag)]() mutable {
|
||||
DEBUG_MARKER_NAME("createTextureViewSwizzleAsyncR")
|
||||
createTextureViewSwizzleCommon(th, srch, r, g, b, a, std::move(tag));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
|
||||
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef image, ImmutableCString&& tag) {
|
||||
@@ -1094,7 +1317,7 @@ void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerTyp
|
||||
}
|
||||
assert_invariant(internalFormat);
|
||||
|
||||
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage);
|
||||
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage, false);
|
||||
assert_invariant(t);
|
||||
|
||||
t->externalTexture = mPlatform.createExternalImageTexture();
|
||||
@@ -1146,7 +1369,7 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
|
||||
}
|
||||
assert_invariant(internalFormat);
|
||||
|
||||
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage);
|
||||
GLTexture* const t = construct<GLTexture>(th, target, 1, 1, width, height, 1, format, usage, false);
|
||||
assert_invariant(t);
|
||||
|
||||
t->externalTexture = mPlatform.createExternalImageTexture();
|
||||
@@ -1186,14 +1409,12 @@ void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
// not relevant for the OpenGL backend
|
||||
}
|
||||
|
||||
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
|
||||
void OpenGLDriver::importTextureCommon(Handle<HwTexture> th, intptr_t const id,
|
||||
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
auto const& gl = mContext;
|
||||
samples = std::clamp(samples, uint8_t(1u), uint8_t(gl.gets.max_samples));
|
||||
GLTexture* t = construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage);
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
|
||||
t->gl.id = GLuint(id);
|
||||
t->gl.imported = true;
|
||||
@@ -1244,6 +1465,46 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
|
||||
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
|
||||
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, ImmutableCString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, false);
|
||||
|
||||
importTextureCommon(th, id, target, levels, format, samples, width, height, depth, usage,
|
||||
std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t const id,
|
||||
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user,
|
||||
ImmutableCString&& tag) {
|
||||
|
||||
// For object creation, the object should be constructed first to determine the initial settings
|
||||
// early. For example, the `asynchronous` field needs to be decided at this stage so that
|
||||
// subsequent backend APIs can handle operations based on this setting.
|
||||
construct<GLTexture>(th, target, levels, samples, width, height, depth, format, usage, true);
|
||||
|
||||
assert_invariant(getJobQueue());
|
||||
|
||||
getJobQueue()->push([this, th, id, target, levels, format, samples, width, height, depth, usage,
|
||||
handler, callback, user, tag=std::move(tag)]() mutable {
|
||||
DEBUG_MARKER_NAME("importTextureAsyncR")
|
||||
importTextureCommon(th, id, target, levels, format, samples, width, height, depth, usage,
|
||||
std::move(tag));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
|
||||
// NOTE: this is called often and must be as efficient as possible.
|
||||
|
||||
@@ -1931,30 +2192,53 @@ void OpenGLDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyIndexBufferCommon(Handle<HwIndexBuffer> ibh) {
|
||||
GLIndexBuffer const* ib = handle_cast<const GLIndexBuffer*>(ibh);
|
||||
auto& gl = mContext;
|
||||
gl.deleteBuffer(ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
|
||||
destruct(ibh, ib);
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
if (ibh) {
|
||||
auto& gl = mContext;
|
||||
GLIndexBuffer const* ib = handle_cast<const GLIndexBuffer*>(ibh);
|
||||
gl.deleteBuffer(ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
|
||||
destruct(ibh, ib);
|
||||
if (ib->asynchronous) {
|
||||
getJobQueue()->push([this, ibh]() {
|
||||
destroyIndexBufferCommon(ibh);
|
||||
});
|
||||
} else {
|
||||
destroyIndexBufferCommon(ibh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyBufferObjectCommon(Handle<HwBufferObject> boh) {
|
||||
GLBufferObject const* bo = handle_cast<const GLBufferObject*>(boh);
|
||||
auto& gl = mContext;
|
||||
// check we're not destroying a buffer that has active mappings
|
||||
assert_invariant(bo->mappingCount == 0);
|
||||
if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
free(bo->gl.buffer);
|
||||
} else {
|
||||
gl.deleteBuffer(bo->gl.id, bo->gl.binding);
|
||||
}
|
||||
destruct(boh, bo);
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
if (boh) {
|
||||
auto& gl = mContext;
|
||||
GLBufferObject const* bo = handle_cast<const GLBufferObject*>(boh);
|
||||
// check we're not destroying a buffer that has active mappings
|
||||
assert_invariant(bo->mappingCount == 0);
|
||||
if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
free(bo->gl.buffer);
|
||||
if (bo->asynchronous) {
|
||||
getJobQueue()->push([this, boh]() {
|
||||
destroyBufferObjectCommon(boh);
|
||||
});
|
||||
} else {
|
||||
gl.deleteBuffer(bo->gl.id, bo->gl.binding);
|
||||
destroyBufferObjectCommon(boh);
|
||||
}
|
||||
destruct(boh, bo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1990,53 +2274,63 @@ void OpenGLDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyTextureCommon(Handle<HwTexture> th) {
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
auto& gl = mContext;
|
||||
if (UTILS_LIKELY(!t->gl.imported)) {
|
||||
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
// drop a reference
|
||||
uint16_t count = 0;
|
||||
if (UTILS_UNLIKELY(t->ref)) {
|
||||
// the common case is that we don't have a ref handle
|
||||
GLTextureRef* const ref = handle_cast<GLTextureRef*>(t->ref);
|
||||
count = --(ref->count);
|
||||
if (count == 0) {
|
||||
destruct(t->ref, ref);
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
// if this was the last reference, we destroy the refcount as well as
|
||||
// the GL texture name itself.
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
if (UTILS_UNLIKELY(t->hwStream)) {
|
||||
detachStream(t);
|
||||
}
|
||||
if (UTILS_UNLIKELY(t->externalTexture)) {
|
||||
mPlatform.destroyExternalImageTexture(t->externalTexture);
|
||||
} else {
|
||||
glDeleteTextures(1, &t->gl.id);
|
||||
}
|
||||
} else {
|
||||
// The Handle<HwTexture> is always destroyed. For extra precaution we also
|
||||
// check that the GLTexture has a trivial destructor.
|
||||
static_assert(std::is_trivially_destructible_v<GLTexture>);
|
||||
}
|
||||
} else {
|
||||
assert_invariant(t->gl.target == GL_RENDERBUFFER);
|
||||
glDeleteRenderbuffers(1, &t->gl.id);
|
||||
}
|
||||
if (t->gl.sidecarRenderBufferMS) {
|
||||
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
|
||||
}
|
||||
} else {
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
}
|
||||
destruct(th, t);
|
||||
}
|
||||
|
||||
void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
if (th) {
|
||||
auto& gl = mContext;
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
|
||||
if (UTILS_LIKELY(!t->gl.imported)) {
|
||||
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
// drop a reference
|
||||
uint16_t count = 0;
|
||||
if (UTILS_UNLIKELY(t->ref)) {
|
||||
// the common case is that we don't have a ref handle
|
||||
GLTextureRef* const ref = handle_cast<GLTextureRef*>(t->ref);
|
||||
count = --(ref->count);
|
||||
if (count == 0) {
|
||||
destruct(t->ref, ref);
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
// if this was the last reference, we destroy the refcount as well as
|
||||
// the GL texture name itself.
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
if (UTILS_UNLIKELY(t->hwStream)) {
|
||||
detachStream(t);
|
||||
}
|
||||
if (UTILS_UNLIKELY(t->externalTexture)) {
|
||||
mPlatform.destroyExternalImageTexture(t->externalTexture);
|
||||
} else {
|
||||
glDeleteTextures(1, &t->gl.id);
|
||||
}
|
||||
} else {
|
||||
// The Handle<HwTexture> is always destroyed. For extra precaution we also
|
||||
// check that the GLTexture has a trivial destructor.
|
||||
static_assert(std::is_trivially_destructible_v<GLTexture>);
|
||||
}
|
||||
} else {
|
||||
assert_invariant(t->gl.target == GL_RENDERBUFFER);
|
||||
glDeleteRenderbuffers(1, &t->gl.id);
|
||||
}
|
||||
if (t->gl.sidecarRenderBufferMS) {
|
||||
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
|
||||
}
|
||||
if (t->asynchronous) {
|
||||
getJobQueue()->push([this, th]() {
|
||||
destroyTextureCommon(th);
|
||||
});
|
||||
} else {
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
destroyTextureCommon(th);
|
||||
}
|
||||
destruct(th, t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2577,7 +2871,7 @@ bool OpenGLDriver::isStereoSupported() {
|
||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||
return false;
|
||||
}
|
||||
switch (mDriverConfig.stereoscopicType) {
|
||||
switch (getDriverConfig().stereoscopicType) {
|
||||
case StereoscopicType::INSTANCED:
|
||||
return mContext.ext.EXT_clip_cull_distance;
|
||||
case StereoscopicType::MULTIVIEW:
|
||||
@@ -2596,7 +2890,7 @@ bool OpenGLDriver::isParallelShaderCompileSupported() {
|
||||
// GL-specific. It would also be nice to inform the engine that they're working with this fake
|
||||
// amortized system, but this fact will become implicit when we generalize this feature for all
|
||||
// backends.
|
||||
if (mDriverConfig.disableAmortizedShaderCompile) {
|
||||
if (getDriverConfig().disableAmortizedShaderCompile) {
|
||||
return mShaderCompilerService.isParallelShaderCompileSupported();
|
||||
}
|
||||
return true;
|
||||
@@ -2618,6 +2912,10 @@ bool OpenGLDriver::isDepthClampSupported() {
|
||||
return getContext().ext.EXT_depth_clamp;
|
||||
}
|
||||
|
||||
bool OpenGLDriver::isAsynchronousModeEnabled() {
|
||||
return getJobQueue() != nullptr;
|
||||
}
|
||||
|
||||
bool OpenGLDriver::isWorkaroundNeeded(Workaround const workaround) {
|
||||
switch (workaround) {
|
||||
case Workaround::SPLIT_EASU:
|
||||
@@ -2799,10 +3097,8 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
|
||||
// Updating driver objects
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
|
||||
void OpenGLDriver::setVertexBufferObjectCommon(Handle<HwVertexBuffer> vbh,
|
||||
uint32_t const index, Handle<HwBufferObject> boh) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLVertexBuffer* vb = handle_cast<GLVertexBuffer *>(vbh);
|
||||
GLBufferObject const* bo = handle_cast<GLBufferObject *>(boh);
|
||||
|
||||
@@ -2822,10 +3118,28 @@ void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateIndexBuffer(
|
||||
Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, uint32_t const byteOffset) {
|
||||
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
|
||||
uint32_t const index, Handle<HwBufferObject> boh) {
|
||||
DEBUG_MARKER()
|
||||
setVertexBufferObjectCommon(vbh, index, boh);
|
||||
}
|
||||
|
||||
void OpenGLDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
|
||||
uint32_t const index, Handle<HwBufferObject> boh, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
getJobQueue()->push([this, vbh, index, boh, handler, callback, user]() mutable {
|
||||
DEBUG_MARKER_NAME("setVertexBufferObjectAsyncR")
|
||||
setVertexBufferObjectCommon(vbh, index, boh);
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
}, jobId);
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateIndexBufferCommon(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t const byteOffset) {
|
||||
auto& gl = mContext;
|
||||
GLIndexBuffer const* ib = handle_cast<GLIndexBuffer *>(ibh);
|
||||
assert_invariant(ib->elementSize == 2 || ib->elementSize == 4);
|
||||
@@ -2839,9 +3153,29 @@ void OpenGLDriver::updateIndexBuffer(
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateBufferObject(
|
||||
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
|
||||
void OpenGLDriver::updateIndexBuffer(
|
||||
Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, uint32_t const byteOffset) {
|
||||
DEBUG_MARKER()
|
||||
updateIndexBufferCommon(ibh, std::move(p), byteOffset);
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
|
||||
BufferDescriptor&& p, uint32_t const byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
getJobQueue()->push([this, ibh, p=std::move(p), byteOffset, handler, callback,
|
||||
user]() mutable {
|
||||
DEBUG_MARKER_NAME("updateIndexBufferAsyncR")
|
||||
updateIndexBufferCommon(ibh, std::move(p), byteOffset);
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
}, jobId);
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateBufferObjectCommon(
|
||||
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
|
||||
|
||||
auto& gl = mContext;
|
||||
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
|
||||
@@ -2874,6 +3208,27 @@ void OpenGLDriver::updateBufferObject(
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateBufferObject(
|
||||
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
|
||||
DEBUG_MARKER()
|
||||
updateBufferObjectCommon(boh, std::move(bd), byteOffset);
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
|
||||
BufferDescriptor&& bd, uint32_t const byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
getJobQueue()->push([this, boh, bd=std::move(bd), byteOffset, handler, callback,
|
||||
user]() mutable {
|
||||
DEBUG_MARKER_NAME("updateBufferObjectAsyncR")
|
||||
updateBufferObjectCommon(boh, std::move(bd), byteOffset);
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
}, jobId);
|
||||
}
|
||||
|
||||
void OpenGLDriver::updateBufferObjectUnsynchronized(
|
||||
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t const byteOffset) {
|
||||
DEBUG_MARKER()
|
||||
@@ -2937,12 +3292,10 @@ void OpenGLDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::update3DImage(Handle<HwTexture> th,
|
||||
void OpenGLDriver::update3DImageCommon(Handle<HwTexture> th,
|
||||
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
|
||||
uint32_t const width, uint32_t const height, uint32_t const depth,
|
||||
PixelBufferDescriptor&& data) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLTexture const* t = handle_cast<GLTexture *>(th);
|
||||
if (data.type == PixelDataType::COMPRESSED) {
|
||||
setCompressedTextureData(t,
|
||||
@@ -2953,6 +3306,33 @@ void OpenGLDriver::update3DImage(Handle<HwTexture> th,
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::update3DImage(Handle<HwTexture> th,
|
||||
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
|
||||
uint32_t const width, uint32_t const height, uint32_t const depth,
|
||||
PixelBufferDescriptor&& data) {
|
||||
DEBUG_MARKER()
|
||||
update3DImageCommon(th, level, xoffset, yoffset, zoffset, width, height, depth,
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
void OpenGLDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
|
||||
uint32_t const level, uint32_t const xoffset, uint32_t const yoffset, uint32_t const zoffset,
|
||||
uint32_t const width, uint32_t const height, uint32_t const depth,
|
||||
PixelBufferDescriptor&& data, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
getJobQueue()->push([this, th, level, xoffset, yoffset, zoffset, width, height, depth,
|
||||
data=std::move(data), handler, callback, user]() mutable {
|
||||
DEBUG_MARKER_NAME("update3DImageAsync")
|
||||
update3DImageCommon(th, level, xoffset, yoffset, zoffset, width, height, depth,
|
||||
std::move(data));
|
||||
// glFlush() should be called when using a shared context for this operation. Without it,
|
||||
// the driver may delay submitting commands to the GPU, preventing other contexts from
|
||||
// seeing the changes immediately. This ensures submitting the current commands right away.
|
||||
glFlush();
|
||||
scheduleCallback(handler, user, callback);
|
||||
}, jobId);
|
||||
}
|
||||
|
||||
void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
@@ -3852,6 +4232,10 @@ void OpenGLDriver::tick(int) {
|
||||
#endif
|
||||
executeEveryNowAndThenOps();
|
||||
getShaderCompilerService().tick();
|
||||
if (getJobWorker()) {
|
||||
// This number is randomly/heuristically chosen. Consider making the number optional.
|
||||
getJobWorker()->process(5);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::beginFrame(
|
||||
@@ -4472,6 +4856,23 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 const workGr
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDriver::queueCommandAsyncR(AsyncCallId jobId, Invocable<void()>&& command, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
assert_invariant(getJobQueue());
|
||||
getJobQueue()->push([this, command=std::move(command), handler, callback, user]() {
|
||||
DEBUG_MARKER_NAME("queueCommandAsync")
|
||||
if (command) {
|
||||
command();
|
||||
}
|
||||
scheduleCallback(handler, user, callback);
|
||||
}, jobId);
|
||||
}
|
||||
|
||||
bool OpenGLDriver::cancelAsyncJob(AsyncCallId jobId) {
|
||||
assert_invariant(getJobQueue());
|
||||
return getJobQueue()->cancel(jobId);
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
template class ConcreteDispatcher<OpenGLDriver>;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "GLDescriptorSetLayout.h"
|
||||
#include "GLMemoryMappedBuffer.h"
|
||||
#include "GLTexture.h"
|
||||
#include "JobQueue.h"
|
||||
#include "ShaderCompilerService.h"
|
||||
|
||||
#include <backend/AcquiredImage.h>
|
||||
@@ -248,6 +249,9 @@ private:
|
||||
return utils::CString{ mContext.state.renderer };
|
||||
}
|
||||
|
||||
JobQueue* getJobQueue() const noexcept { return mJobQueue.get(); }
|
||||
JobWorker* getJobWorker() const noexcept { return mJobWorker.get(); }
|
||||
|
||||
template<typename T>
|
||||
friend class ConcreteDispatcher;
|
||||
|
||||
@@ -358,6 +362,34 @@ private:
|
||||
static GLsizei getAttachments(AttachmentArray& attachments, TargetBufferFlags buffers,
|
||||
bool isDefaultFramebuffer) noexcept;
|
||||
|
||||
// Common methods
|
||||
void createTextureCommon(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, utils::ImmutableCString&& tag);
|
||||
void update3DImageCommon(Handle<HwTexture> th,
|
||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
PixelBufferDescriptor&& data);
|
||||
void createTextureViewSwizzleCommon(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b,
|
||||
TextureSwizzle a, utils::ImmutableCString&& tag);
|
||||
void importTextureCommon(Handle<HwTexture> th, intptr_t id, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, utils::ImmutableCString&& tag);
|
||||
void createBufferObjectCommon(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag);
|
||||
void setVertexBufferObjectCommon(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||
Handle<HwBufferObject> boh);
|
||||
void updateBufferObjectCommon(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
|
||||
uint32_t byteOffset);
|
||||
void createIndexBufferCommon(Handle<HwIndexBuffer> ibh, ElementType const elementType,
|
||||
uint32_t indexCount, BufferUsage const usage, utils::ImmutableCString&& tag);
|
||||
void updateIndexBufferCommon(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t const byteOffset);
|
||||
void destroyTextureCommon(Handle<HwTexture> th);
|
||||
void destroyBufferObjectCommon(Handle<HwBufferObject> boh);
|
||||
void destroyIndexBufferCommon(Handle<HwIndexBuffer> ibh);
|
||||
|
||||
// state required to represent the current render pass
|
||||
Handle<HwRenderTarget> mRenderPassTarget;
|
||||
RenderPassParams mRenderPassParams;
|
||||
@@ -413,15 +445,15 @@ private:
|
||||
void executeEveryNowAndThenOps() noexcept;
|
||||
std::vector<std::function<bool()>> mEveryNowAndThenOps;
|
||||
|
||||
const Platform::DriverConfig mDriverConfig;
|
||||
Platform::DriverConfig const& getDriverConfig() const noexcept { return mDriverConfig; }
|
||||
|
||||
// for ES2 sRGB support
|
||||
GLSwapChain* mCurrentDrawSwapChain = nullptr;
|
||||
bool mRec709OutputColorspace = false;
|
||||
|
||||
PushConstantBundle* mCurrentPushConstants = nullptr;
|
||||
PipelineLayout::SetLayout mCurrentSetLayout;
|
||||
|
||||
JobQueue::Ptr mJobQueue;
|
||||
JobWorker::Ptr mJobWorker;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -19,12 +19,16 @@
|
||||
|
||||
#include "DriverBase.h"
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class OpenGLDriverBase : public DriverBase {
|
||||
protected:
|
||||
explicit OpenGLDriverBase(const Platform::DriverConfig& driverConfig)
|
||||
: DriverBase(driverConfig) {}
|
||||
~OpenGLDriverBase() override;
|
||||
|
||||
public:
|
||||
|
||||
@@ -254,8 +254,14 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
mPushConstants.reserve(totalConstantCount);
|
||||
mPushConstantFragmentStageOffset = vertexConstants.size();
|
||||
auto const transformAndAdd = [&](Program::PushConstant const& constant) {
|
||||
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
|
||||
mPushConstants.push_back({loc, constant.type});
|
||||
if (!constant.name.empty()) {
|
||||
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
|
||||
mPushConstants.push_back({loc, constant.type});
|
||||
} else {
|
||||
// If the constant is not named, then we assume it will not be referenced in this
|
||||
// program.
|
||||
mPushConstants.push_back({ -1, constant.type });
|
||||
}
|
||||
};
|
||||
std::for_each(vertexConstants.cbegin(), vertexConstants.cend(), transformAndAdd);
|
||||
std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), transformAndAdd);
|
||||
|
||||
@@ -79,6 +79,7 @@ static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context
|
||||
static void process_OVR_multiview2(OpenGLContext const& context, int32_t eyeCount, char* source,
|
||||
size_t len) noexcept;
|
||||
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
|
||||
static std::string_view process_countBits(OpenGLContext& context) noexcept;
|
||||
static std::array<std::string_view, 3> splitShaderSource(std::string_view source);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -779,6 +780,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
|
||||
// add support for ARB_shading_language_packing if needed
|
||||
auto const packingFunctions = process_ARB_shading_language_packing(context);
|
||||
auto const countBitsFunctions = process_countBits(context);
|
||||
|
||||
// split shader source, so we can insert the specialization constants and the packing
|
||||
// functions
|
||||
@@ -789,10 +791,10 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
version = "#version 310 es\n";
|
||||
}
|
||||
|
||||
std::array<std::string_view, 5> sources = {
|
||||
std::array<std::string_view, 6> sources = {
|
||||
version, prolog,
|
||||
{ specializationConstantString.data(), specializationConstantString.size() },
|
||||
packingFunctions,
|
||||
packingFunctions, countBitsFunctions,
|
||||
{ body.data(), body.size() - 1 } // null-terminated
|
||||
};
|
||||
|
||||
@@ -803,8 +805,8 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
[](std::string_view s) { return !s.empty(); });
|
||||
size_t const count = std::distance(sources.begin(), partitionPoint);
|
||||
|
||||
std::array<const char*, 5> shaderStrings;
|
||||
std::array<GLint, 5> lengths;
|
||||
std::array<const char*, 6> shaderStrings;
|
||||
std::array<GLint, 6> lengths;
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
shaderStrings[j] = sources[j].data();
|
||||
lengths[j] = GLint(sources[j].size());
|
||||
@@ -1085,6 +1087,22 @@ UTILS_NOINLINE
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ std::string_view process_countBits(OpenGLContext& context) noexcept {
|
||||
using namespace std::literals;
|
||||
if (context.isAtLeastGL<4, 0>() || context.isAtLeastGLES<3, 1>()) {
|
||||
return ""sv;
|
||||
}
|
||||
return R"(
|
||||
// https://graphics.stanford.edu/%7Eseander/bithacks.html
|
||||
int bitCount(highp uint value) {
|
||||
value = value - ((value >> 1u) & 0x55555555u);
|
||||
value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);
|
||||
return int(((value + (value >> 4u) & 0xF0F0F0Fu) * 0x1010101u) >> 24u);
|
||||
}
|
||||
)"sv;
|
||||
}
|
||||
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
|
||||
// macOS doesn't support GL_ARB_shading_language_packing
|
||||
// Also GLES3.0 didn't have the full set of packing/unpacking functions
|
||||
|
||||
@@ -267,8 +267,6 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
||||
eglDupNativeFenceFDANDROID =
|
||||
PFNEGLDUPNATIVEFENCEFDANDROIDPROC(eglGetProcAddress(
|
||||
"eglDupNativeFenceFDANDROID"));
|
||||
} else {
|
||||
LOG(ERROR) << "EGL_ANDROID_native_fence_sync not supported!";
|
||||
}
|
||||
|
||||
mAssertNativeWindowIsValid = driverConfig.assertNativeWindowIsValid;
|
||||
@@ -298,9 +296,18 @@ bool PlatformEGLAndroid::queryCompositorTiming(SwapChain const* swapchain,
|
||||
|
||||
AndroidFrameCallback::Timeline const preferredTimeline{
|
||||
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
|
||||
outCompositorTiming->frameTime = preferredTimeline.frameTime;
|
||||
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
|
||||
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
|
||||
// FIXME: expectedPresentLatency might reflect the previous frame's value because
|
||||
// the choreographer's callback can happen before (good) or after (bad) us.
|
||||
// This problem is mitigated by storing the latency instead of the deadline,
|
||||
// because it generally is constant frame to frame.
|
||||
if (UTILS_LIKELY(preferredTimeline.expectedPresentTime > preferredTimeline.frameTime)) {
|
||||
// latency can never be negative, let's be safe
|
||||
outCompositorTiming->expectedPresentLatency =
|
||||
preferredTimeline.expectedPresentTime - preferredTimeline.frameTime;
|
||||
} else {
|
||||
// fake a reasonable value (33ms)
|
||||
outCompositorTiming->expectedPresentLatency = 33'000'000;
|
||||
}
|
||||
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
|
||||
|
||||
@@ -54,17 +54,12 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
|
||||
// Check if we can just memcpy directly to the GPU memory.
|
||||
bool const isMemcopyable = mBuffer->getGpuBuffer()->allocationInfo.pMappedData != nullptr;
|
||||
|
||||
// In the case of UNIFORMS, check that is available to see to know if a memcpy is possible.
|
||||
// This works regardless if it's a full or partial update of the buffer.
|
||||
bool const isUniformAndAvailable = getBinding() == VulkanBufferBinding::UNIFORM && isAvailable;
|
||||
|
||||
// In the case the content is marked as memory mapped or static, is guaranteed to be safe to do
|
||||
// a memcpy if its available.
|
||||
bool const isStaticOrShared =
|
||||
any(mUsage & (BufferUsage::STATIC | BufferUsage::SHARED_WRITE_BIT));
|
||||
bool const useMemcpy =
|
||||
((isUniformAndAvailable && mStagingBufferBypassEnabled) || isStaticOrShared) &&
|
||||
isMemcopyable;
|
||||
((isAvailable && mStagingBufferBypassEnabled) || isStaticOrShared) && isMemcopyable;
|
||||
if (useMemcpy) {
|
||||
char* dest = static_cast<char*>(mBuffer->getGpuBuffer()->allocationInfo.pMappedData) +
|
||||
byteOffset;
|
||||
|
||||
@@ -76,5 +76,4 @@ VkImageSubresourceRange VulkanAttachment::getSubresourceRange() const {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
@@ -90,6 +91,19 @@ public:
|
||||
return selectMemoryType(mMemoryProperties, types, reqs);
|
||||
}
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
inline void addPipelineCachePrewarmExternalFormat(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
mPipelineCachePrewarmExternalFormats.push_back(format);
|
||||
}
|
||||
|
||||
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
|
||||
return mDepthStencilFormats;
|
||||
}
|
||||
@@ -106,6 +120,18 @@ public:
|
||||
return mPhysicalDeviceProperties.properties.vendorID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of pre-registered external formats for prewarming the Vulkan
|
||||
* pipeline cache.
|
||||
*
|
||||
* @return A list containing an external format number, YCbCr color model conversion,
|
||||
* and YCbCr color range.
|
||||
*/
|
||||
inline const std::vector<VulkanPlatform::ExternalYcbcrFormat>&
|
||||
getPipelineCachePrewarmExternalFormats() const noexcept {
|
||||
return mPipelineCachePrewarmExternalFormats;
|
||||
}
|
||||
|
||||
inline VkExternalFenceHandleTypeFlags getFenceExportFlags() const noexcept {
|
||||
return mFenceExportFlags;
|
||||
}
|
||||
@@ -126,6 +152,10 @@ public:
|
||||
return mDebugUtilsSupported;
|
||||
}
|
||||
|
||||
inline bool isDynamicRenderingSupported() const noexcept {
|
||||
return mDynamicRenderingFeatures.dynamicRendering == VK_TRUE;
|
||||
}
|
||||
|
||||
inline bool isMultiviewEnabled() const noexcept {
|
||||
return mPhysicalDeviceVk11Features.multiview == VK_TRUE;
|
||||
}
|
||||
@@ -150,14 +180,33 @@ public:
|
||||
return mIsUnifiedMemoryArchitecture;
|
||||
}
|
||||
|
||||
inline bool stagingBufferBypassEnabled() const noexcept {
|
||||
return mStagingBufferBypassEnabled;
|
||||
inline bool isVertexInputDynamicStateSupported() const noexcept {
|
||||
return mVertexInputDynamicStateSupported;
|
||||
}
|
||||
|
||||
inline bool pipelineCreationFeedbackSupported() const noexcept {
|
||||
return mPipelineCreationFeedbackSupported;
|
||||
}
|
||||
|
||||
inline bool asyncPipelineCachePrewarmingEnabled() const noexcept {
|
||||
return mAsyncPipelineCachePrewarmingEnabled;
|
||||
}
|
||||
|
||||
inline bool parallelShaderCompilationDisabled() const noexcept {
|
||||
return mParallelShaderCompileDisabled;
|
||||
}
|
||||
|
||||
inline bool stagingBufferBypassEnabled() const noexcept {
|
||||
return mStagingBufferBypassEnabled;
|
||||
}
|
||||
|
||||
inline bool shouldUsePipelineCachePrewarming() const noexcept {
|
||||
return asyncPipelineCachePrewarmingEnabled() &&
|
||||
!parallelShaderCompilationDisabled() &&
|
||||
isVertexInputDynamicStateSupported() &&
|
||||
isDynamicRenderingSupported();
|
||||
}
|
||||
|
||||
private:
|
||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||
@@ -169,6 +218,9 @@ private:
|
||||
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
};
|
||||
VkPhysicalDeviceDynamicRenderingFeaturesKHR mDynamicRenderingFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR,
|
||||
};
|
||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR mPortabilitySubsetFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||
// By default, on platforms where we don't have portability subset, then this feature must
|
||||
@@ -179,17 +231,26 @@ private:
|
||||
|
||||
VkExternalFenceHandleTypeFlags mFenceExportFlags = {};
|
||||
|
||||
// These are options that are either supported or not supported in the current
|
||||
// device and instance.
|
||||
bool mDebugMarkersSupported = false;
|
||||
bool mDebugUtilsSupported = false;
|
||||
bool mLazilyAllocatedMemorySupported = false;
|
||||
bool mProtectedMemorySupported = false;
|
||||
bool mIsUnifiedMemoryArchitecture = false;
|
||||
bool mStagingBufferBypassEnabled = false;
|
||||
bool mLazilyAllocatedMemorySupported = false;
|
||||
bool mPipelineCreationFeedbackSupported = false;
|
||||
bool mProtectedMemorySupported = false;
|
||||
bool mVertexInputDynamicStateSupported = false;
|
||||
|
||||
// These are options that can be enabled or disabled at an application level.
|
||||
bool mAsyncPipelineCachePrewarmingEnabled = false;
|
||||
bool mParallelShaderCompileDisabled = false;
|
||||
bool mStagingBufferBypassEnabled = false;
|
||||
|
||||
fvkutils::VkFormatList mDepthStencilFormats;
|
||||
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
||||
|
||||
std::vector<VulkanPlatform::ExternalYcbcrFormat> mPipelineCachePrewarmExternalFormats;
|
||||
|
||||
// For convenience so that VulkanPlatform can initialize the private fields.
|
||||
friend class VulkanPlatform;
|
||||
};
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <set> // For VulkanDriver::debugCommandBegin
|
||||
@@ -151,6 +152,28 @@ static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
|
||||
cbData->cb(cbData->sync, cbData->userData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shorthand for converting a description for an external YCbCr format used for
|
||||
* pipeline cache prewarming to the params for the actual YCbCr conversion.
|
||||
*/
|
||||
inline VulkanYcbcrConversionCache::Params getYcbcrConversionParams(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
return VulkanYcbcrConversionCache::Params {
|
||||
.conversion = {
|
||||
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(format.ycbcrModelConversion),
|
||||
.r = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_R, 0),
|
||||
.g = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_G, 1),
|
||||
.b = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_B, 2),
|
||||
.a = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_A, 3),
|
||||
.ycbcrRange = fvkutils::getYcbcrRangeFilament(format.ycbcrRange),
|
||||
.xChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.yChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.chromaFilter = SamplerMagFilter::NEAREST,
|
||||
},
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.externalFormat = format.externalFormat,
|
||||
};
|
||||
}
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
@@ -217,7 +240,8 @@ Dispatcher VulkanDriver::getDispatcher() const noexcept {
|
||||
|
||||
VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
Platform::DriverConfig const& driverConfig)
|
||||
: mPlatform(platform),
|
||||
: DriverBase(driverConfig),
|
||||
mPlatform(platform),
|
||||
mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck,
|
||||
driverConfig.disableHeapHandleTags),
|
||||
// Note that we always create the default rendertarget before createDefaultRenderTarget(). We
|
||||
@@ -233,7 +257,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(),
|
||||
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext, &mSemaphoreManager),
|
||||
mPipelineLayoutCache(mPlatform->getDevice()),
|
||||
mPipelineCache(mPlatform->getDevice(), mContext),
|
||||
mPipelineCache(*this, mPlatform->getDevice(), mContext),
|
||||
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
|
||||
mBufferCache(mContext, mResourceManager, mAllocator),
|
||||
mFramebufferCache(mPlatform->getDevice()),
|
||||
@@ -249,7 +273,13 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
mStreamedImageManager(&mExternalImageManager),
|
||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||
mIsMSAASwapChainSupported(false), // TODO: support MSAA swapchain
|
||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||
mAcquireSwapChainInMakeCurrent(
|
||||
driverConfig.featureFlagManager ?
|
||||
driverConfig.featureFlagManager->features.backend.vulkan.enable_acquire_swapchain_in_make_current :
|
||||
false),
|
||||
mStereoscopicType(driverConfig.stereoscopicType),
|
||||
mStereoscopicEyeCount(driverConfig.stereoscopicEyeCount),
|
||||
mAsynchronousMode(driverConfig.asynchronousMode) {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
DebugUtils::mSingleton =
|
||||
@@ -601,6 +631,12 @@ void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType ele
|
||||
mResourceManager.associateHandle(ibh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createIndexBufferAsyncR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
uint32_t indexCount, BufferUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
||||
if (!ibh) {
|
||||
return;
|
||||
@@ -619,6 +655,12 @@ void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
||||
mResourceManager.associateHandle(boh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createBufferObjectAsyncR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||
if (!boh) {
|
||||
return;
|
||||
@@ -646,6 +688,13 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
mResourceManager.associateHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureAsyncR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback callback,
|
||||
void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
|
||||
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
|
||||
@@ -668,6 +717,13 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
mResourceManager.associateHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureViewSwizzleAsyncR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user, utils::ImmutableCString&& tag) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef externalImage, utils::ImmutableCString&& tag) {
|
||||
@@ -742,6 +798,16 @@ void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
||||
mResourceManager.associateHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::importTextureAsyncR(Handle<HwTexture> th, intptr_t id,
|
||||
SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||
TextureUsage usage, CallbackHandler* handler, CallbackHandler::Callback callback,
|
||||
void* user, utils::ImmutableCString&& tag) {
|
||||
// not supported in this backend
|
||||
assert_invariant(false && "Not supported in Vulkan backend");
|
||||
mResourceManager.associateHandle(th.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
if (!th) {
|
||||
return;
|
||||
@@ -758,6 +824,76 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
|
||||
program);
|
||||
vprogram.inc();
|
||||
mResourceManager.associateHandle(ph.getId(), std::move(tag));
|
||||
|
||||
if (!mContext.shouldUsePipelineCachePrewarming()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If async prewarming is enabled, let's find the proper layout and build the pipeline.
|
||||
std::array<resource_ptr<VulkanDescriptorSetLayout>, MAX_DESCRIPTOR_SET_COUNT> layouts {};
|
||||
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vkLayouts {};
|
||||
bool hasExternalSamplers = false;
|
||||
for (const auto& layoutBinding : program.getDescriptorSetLayouts()) {
|
||||
DescriptorSetLayout layoutDescription = layoutBinding.layout;
|
||||
auto layoutHandle = mResourceManager.allocHandle<VulkanDescriptorSetLayout>();
|
||||
auto layout = mDescriptorSetLayoutCache.createLayout(layoutHandle, std::move(layoutDescription));
|
||||
layouts[layoutBinding.set] = layout;
|
||||
vkLayouts[layoutBinding.set] = layout->getVkLayout();
|
||||
if (layout->bitmask.externalSampler.count() > 0) {
|
||||
hasExternalSamplers = true;
|
||||
}
|
||||
}
|
||||
|
||||
StereoscopicType stereoscopicType = mStereoscopicType;
|
||||
if (stereoscopicType == StereoscopicType::MULTIVIEW && !program.isMultiview()) {
|
||||
stereoscopicType = StereoscopicType::NONE;
|
||||
}
|
||||
|
||||
// Base case - build the pipeline without any external samplers.
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
*vprogram.get(),
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
|
||||
if (!hasExternalSamplers) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have external samplers, let's do this again with the external samplers
|
||||
// specified.
|
||||
for (const auto& format : mContext.getPipelineCachePrewarmExternalFormats()) {
|
||||
// The values that seem to matter in terms of cache hits here are the model conversion,
|
||||
// and model range. We need some value for externalFormat that is known to support that
|
||||
// pair of values, but we need not find every possible externalFormat. As we test on
|
||||
// more devices, this may change.
|
||||
VkSamplerYcbcrConversion vkConversion = mYcbcrConversionCache.getConversion(
|
||||
getYcbcrConversionParams(format));
|
||||
VkSampler externalSampler = mSamplerCache.getSampler({.sampler = {}, .conversion = vkConversion});
|
||||
|
||||
// Update all layouts to use the external samplers.
|
||||
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; ++i) {
|
||||
if (!layouts[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For cache prewarming, we don't need every single possible combination of external sampler
|
||||
// formats. It seems to be enough, in practicce, to simply run through a list of the types of
|
||||
// samplers that *might* appear. As long as the real pipeline is close enough to something that
|
||||
// the driver has seen before, we are able to get a cache hit.
|
||||
utils::FixedCapacityVector<VkSampler> externalSamplers (layouts[i]->bitmask.externalSampler.count(), externalSampler);
|
||||
vkLayouts[i] = mDescriptorSetLayoutCache.getVkLayout(
|
||||
layouts[i]->bitmask, layouts[i]->bitmask.externalSampler, externalSamplers);
|
||||
}
|
||||
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
*vprogram.get(),
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
@@ -772,7 +908,7 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils:
|
||||
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
|
||||
|
||||
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
|
||||
std::move(std::move(*mDefaultRenderTarget.get())));
|
||||
std::move(*mDefaultRenderTarget.get()));
|
||||
|
||||
mDefaultRenderTarget = renderTarget;
|
||||
mResourceManager.associateHandle(rth.getId(), std::move(tag));
|
||||
@@ -1000,14 +1136,26 @@ Handle<HwIndexBuffer> VulkanDriver::createIndexBufferS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwIndexBuffer> VulkanDriver::createIndexBufferAsyncS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanIndexBuffer>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> VulkanDriver::createBufferObjectS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> VulkanDriver::createBufferObjectAsyncS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanBufferObject>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::createTextureS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::createTextureAsyncS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::createTextureViewS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
@@ -1016,6 +1164,10 @@ Handle<HwTexture> VulkanDriver::createTextureViewSwizzleS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::createTextureViewSwizzleAsyncS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::createTextureExternalImage2S() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
@@ -1032,6 +1184,30 @@ Handle<HwTexture> VulkanDriver::importTextureS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> VulkanDriver::importTextureAsyncS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanTexture>();
|
||||
}
|
||||
|
||||
AsyncCallId VulkanDriver::update3DImageAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId VulkanDriver::setVertexBufferObjectAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId VulkanDriver::updateBufferObjectAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
AsyncCallId VulkanDriver::updateIndexBufferAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
Handle<HwRenderPrimitive> VulkanDriver::createRenderPrimitiveS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanRenderPrimitive>();
|
||||
}
|
||||
@@ -1090,6 +1266,11 @@ MemoryMappedBufferHandle VulkanDriver::mapBufferS() noexcept {
|
||||
return mResourceManager.allocHandle<VulkanMemoryMappedBuffer>();
|
||||
}
|
||||
|
||||
AsyncCallId VulkanDriver::queueCommandAsyncS() noexcept {
|
||||
// TODO: implement this.
|
||||
return InvalidAsyncCallId;
|
||||
}
|
||||
|
||||
void VulkanDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
|
||||
if (!mmbh) {
|
||||
return;
|
||||
@@ -1417,7 +1598,7 @@ bool VulkanDriver::isStereoSupported() {
|
||||
}
|
||||
|
||||
bool VulkanDriver::isParallelShaderCompileSupported() {
|
||||
return false;
|
||||
return mContext.shouldUsePipelineCachePrewarming();
|
||||
}
|
||||
|
||||
bool VulkanDriver::isDepthStencilResolveSupported() {
|
||||
@@ -1437,6 +1618,10 @@ bool VulkanDriver::isDepthClampSupported() {
|
||||
return mContext.isDepthClampSupported();
|
||||
}
|
||||
|
||||
bool VulkanDriver::isAsynchronousModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
switch (workaround) {
|
||||
case Workaround::SPLIT_EASU: {
|
||||
@@ -1545,6 +1730,12 @@ void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
|
||||
vb->setBuffer(bo, index);
|
||||
}
|
||||
|
||||
void VulkanDriver::setVertexBufferObjectAsyncR(AsyncCallId jobId, Handle<HwVertexBuffer> vbh,
|
||||
uint32_t index, Handle<HwBufferObject> boh, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t byteOffset) {
|
||||
VulkanCommandBuffer& commands = mCommands.get();
|
||||
@@ -1555,6 +1746,12 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void VulkanDriver::updateIndexBufferAsyncR(AsyncCallId jobId, Handle<HwIndexBuffer> ibh,
|
||||
BufferDescriptor&& p, uint32_t byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
|
||||
uint32_t byteOffset) {
|
||||
VulkanCommandBuffer& commands = mCommands.get();
|
||||
@@ -1567,6 +1764,12 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
|
||||
scheduleDestroy(std::move(bd));
|
||||
}
|
||||
|
||||
void VulkanDriver::updateBufferObjectAsyncR(AsyncCallId jobId, Handle<HwBufferObject> boh,
|
||||
BufferDescriptor&& bd, uint32_t byteOffset, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
|
||||
BufferDescriptor&& bd, uint32_t byteOffset) {
|
||||
VulkanCommandBuffer& commands = mCommands.get();
|
||||
@@ -1594,6 +1797,13 @@ void VulkanDriver::update3DImage(Handle<HwTexture> th, uint32_t level, uint32_t
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
|
||||
void VulkanDriver::update3DImageAsyncR(AsyncCallId jobId, Handle<HwTexture> th,
|
||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width,
|
||||
uint32_t height, uint32_t depth, PixelBufferDescriptor&& data, CallbackHandler* handler,
|
||||
CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
void VulkanDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
|
||||
}
|
||||
|
||||
@@ -1688,7 +1898,11 @@ void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
if (callback) {
|
||||
scheduleCallback(handler, user, callback);
|
||||
if (mContext.shouldUsePipelineCachePrewarming()) {
|
||||
mPipelineCache.addCachePrewarmCallback(handler, callback, user);
|
||||
} else {
|
||||
scheduleCallback(handler, user, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1696,9 +1910,6 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
auto rt = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, rth);
|
||||
VkExtent2D const extent = rt->getExtent();
|
||||
|
||||
assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0);
|
||||
|
||||
VulkanCommandBuffer* commandBuffer = rt->isProtected() ?
|
||||
&mCommands.getProtected() : &mCommands.get();
|
||||
@@ -1713,9 +1924,16 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
if (sc->isFirstRenderPass()) {
|
||||
discardStart |= TargetBufferFlags::COLOR;
|
||||
sc->markFirstRenderPass();
|
||||
acquireNextSwapchainImage();
|
||||
}
|
||||
}
|
||||
|
||||
// Note that retrieving the extent must come after the acquireNextSwapchainImage() above;
|
||||
// otherwise it might be 0.
|
||||
VkExtent2D const extent = rt->getExtent();
|
||||
|
||||
assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
if (rt->hasDepth()) {
|
||||
auto depth = rt->getDepth();
|
||||
@@ -1926,19 +2144,16 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
ASSERT_PRECONDITION_NON_FATAL(drawSch == readSch,
|
||||
"Vulkan driver does not support distinct draw/read swap chains.");
|
||||
|
||||
// Before we can render into the new swapchain, we need to make sure the default render target
|
||||
// releases its old bound swapchain image.
|
||||
mDefaultRenderTarget->releaseSwapchain();
|
||||
|
||||
resource_ptr<VulkanSwapChain> swapChain =
|
||||
resource_ptr<VulkanSwapChain>::cast(&mResourceManager, drawSch);
|
||||
mCurrentSwapChain = swapChain;
|
||||
|
||||
bool resized = false;
|
||||
swapChain->acquire(resized);
|
||||
|
||||
if (resized) {
|
||||
mFramebufferCache.resetFramebuffers();
|
||||
}
|
||||
|
||||
if (UTILS_LIKELY(mDefaultRenderTarget)) {
|
||||
mDefaultRenderTarget->bindToSwapChain(swapChain);
|
||||
if (mAcquireSwapChainInMakeCurrent) {
|
||||
acquireNextSwapchainImage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2110,6 +2325,14 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
auto dstTarget = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, dst);
|
||||
auto srcTarget = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, src);
|
||||
|
||||
// This is a valid use of the api. We need to make sure that the swapchain image has been
|
||||
// acquired and associated with the default render target. It's okay to call
|
||||
// acquireNextSwapchainImage() even if a swapchain image has already been bound to the default
|
||||
// render target.
|
||||
if (dstTarget == mDefaultRenderTarget) {
|
||||
acquireNextSwapchainImage();
|
||||
}
|
||||
|
||||
VkFilter const vkfilter = (filter == SamplerMagFilter::NEAREST) ?
|
||||
VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||
|
||||
@@ -2397,6 +2620,16 @@ void VulkanDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
mQueryManager.endQuery(&(mCommands.get()), vtq);
|
||||
}
|
||||
|
||||
void VulkanDriver::queueCommandAsyncR(AsyncCallId jobId, utils::Invocable<void()>&& command,
|
||||
CallbackHandler* handler, CallbackHandler::Callback const callback, void* user) {
|
||||
// TODO: implement this.
|
||||
}
|
||||
|
||||
bool VulkanDriver::cancelAsyncJob(AsyncCallId jobId) {
|
||||
// TODO: implement this.
|
||||
return false;
|
||||
}
|
||||
|
||||
void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
|
||||
DriverBase::debugCommandBegin(cmds, synchronous, methodName);
|
||||
#ifndef NDEBUG
|
||||
@@ -2431,6 +2664,25 @@ void VulkanDriver::endCommandRecording() {
|
||||
mDescriptorSetCache.resetCachedState();
|
||||
}
|
||||
|
||||
void VulkanDriver::acquireNextSwapchainImage() {
|
||||
assert_invariant(mCurrentSwapChain);
|
||||
assert_invariant(mDefaultRenderTarget);
|
||||
|
||||
// Swapchain has already been bound to the default render target. We just return.
|
||||
if (mDefaultRenderTarget->isSwapchainBound()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool resized = false;
|
||||
mCurrentSwapChain->acquire(resized);
|
||||
if (resized) {
|
||||
mFramebufferCache.resetFramebuffers();
|
||||
}
|
||||
// Note that ordering this after the above lines is necessary since we set the swapchain image
|
||||
// to the render target in bindSwapChain().
|
||||
mDefaultRenderTarget->bindSwapChain(mCurrentSwapChain);
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
template class ConcreteDispatcher<VulkanDriver>;
|
||||
|
||||
|
||||
@@ -132,6 +132,8 @@ private:
|
||||
// Flush the current command buffer and reset the pipeline state.
|
||||
void endCommandRecording();
|
||||
|
||||
void acquireNextSwapchainImage();
|
||||
|
||||
VulkanPlatform* mPlatform = nullptr;
|
||||
fvkmemory::ResourceManager mResourceManager;
|
||||
|
||||
@@ -160,7 +162,6 @@ private:
|
||||
VulkanExternalImageManager mExternalImageManager;
|
||||
VulkanStreamedImageManager mStreamedImageManager;
|
||||
|
||||
|
||||
// This maps a VulkanSwapchain to a native swapchain. VulkanSwapchain should have a copy of the
|
||||
// Platform::Swapchain pointer, but queryFrameTimestamps() and queryCompositorTiming() are
|
||||
// synchronous calls, making access to VulkanSwapchain unsafe (this difference vs other backends
|
||||
@@ -204,7 +205,10 @@ private:
|
||||
|
||||
bool const mIsSRGBSwapChainSupported;
|
||||
bool const mIsMSAASwapChainSupported;
|
||||
bool const mAcquireSwapChainInMakeCurrent;
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
uint8_t const mStereoscopicEyeCount;
|
||||
backend::AsynchronousMode const mAsynchronousMode;
|
||||
|
||||
// setAcquiredImage is a DECL_DRIVER_API_SYNCHRONOUS_N which means we don't necessarily have the
|
||||
// data to process it at call time. So we store it and process it during updateStreams.
|
||||
|
||||
@@ -100,18 +100,18 @@ inline VkShaderStageFlags getVkStage(backend::ShaderStage stage) {
|
||||
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
|
||||
BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
||||
BitmaskGroup mask;
|
||||
for (auto const& binding: layout.bindings) {
|
||||
switch (binding.type) {
|
||||
for (auto const& descriptor: layout.descriptors) {
|
||||
switch (descriptor.type) {
|
||||
case DescriptorType::UNIFORM_BUFFER: {
|
||||
if ((binding.flags & DescriptorFlags::DYNAMIC_OFFSET) != DescriptorFlags::NONE) {
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.dynamicUbo);
|
||||
if ((descriptor.flags & DescriptorFlags::DYNAMIC_OFFSET) != DescriptorFlags::NONE) {
|
||||
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.dynamicUbo);
|
||||
} else {
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.ubo);
|
||||
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.ubo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
|
||||
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.externalSampler);
|
||||
UTILS_FALLTHROUGH;
|
||||
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
@@ -139,11 +139,11 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
||||
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.sampler);
|
||||
break;
|
||||
}
|
||||
case DescriptorType::INPUT_ATTACHMENT: {
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.inputAttachment);
|
||||
fromStageFlags(descriptor.stageFlags, descriptor.binding, mask.inputAttachment);
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SHADER_STORAGE_BUFFER:
|
||||
@@ -265,24 +265,31 @@ void VulkanDescriptorSet::addNewSet(VkDescriptorSet vkSet, OnRecycle&& onRecycle
|
||||
|
||||
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
|
||||
mRangeCount = 0;
|
||||
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
||||
uint32_t offset = 0;
|
||||
|
||||
// The range is laid out so that the vertex constants are defined as the first set of bytes,
|
||||
// followed by fragment and compute. This means we need to keep track of the offset for each
|
||||
// stage. We do the bookeeping in mDescriptions.
|
||||
for (auto stage: { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
||||
auto const& constants = program.getPushConstants(stage);
|
||||
if (constants.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& description = mDescriptions[(uint8_t) stage];
|
||||
// We store the type of the constant for type-checking when writing.
|
||||
auto& types = mTypes[(uint8_t) stage];
|
||||
types.reserve(constants.size());
|
||||
std::for_each(constants.cbegin(), constants.cend(), [&types] (Program::PushConstant t) {
|
||||
types.push_back(t.type);
|
||||
});
|
||||
description.types.reserve(constants.size());
|
||||
std::for_each(constants.cbegin(), constants.cend(),
|
||||
[&description](Program::PushConstant t) { description.types.push_back(t.type); });
|
||||
|
||||
uint32_t const constantsSize = (uint32_t) constants.size() * ENTRY_SIZE;
|
||||
mRanges[mRangeCount++] = {
|
||||
.stageFlags = getVkStage(stage),
|
||||
.offset = 0,
|
||||
.size = (uint32_t) constants.size() * ENTRY_SIZE,
|
||||
.offset = offset,
|
||||
.size = constantsSize,
|
||||
};
|
||||
description.offset = offset;
|
||||
offset += constantsSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +297,10 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
|
||||
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
|
||||
|
||||
uint32_t binaryValue = 0;
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage];
|
||||
auto const& description = mDescriptions[(uint8_t) stage];
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = description.types;
|
||||
uint32_t const offset = description.offset;
|
||||
|
||||
if (std::holds_alternative<bool>(value)) {
|
||||
assert_invariant(types[index] == ConstantType::BOOL);
|
||||
bool const bval = std::get<bool>(value);
|
||||
@@ -304,7 +314,8 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
|
||||
int const ival = std::get<int>(value);
|
||||
binaryValue = *reinterpret_cast<uint32_t const*>(&ival);
|
||||
}
|
||||
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
|
||||
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), offset + index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
&binaryValue);
|
||||
}
|
||||
|
||||
@@ -387,8 +398,9 @@ VulkanRenderTarget::VulkanRenderTarget()
|
||||
|
||||
VulkanRenderTarget::~VulkanRenderTarget() = default;
|
||||
|
||||
void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain) {
|
||||
void VulkanRenderTarget::bindSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain) {
|
||||
assert_invariant(!mOffscreen);
|
||||
assert_invariant(!mInfo->colors[0]);
|
||||
|
||||
VkExtent2D const extent = swapchain->getExtent();
|
||||
width = extent.width;
|
||||
@@ -396,7 +408,8 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
|
||||
mProtected = swapchain->isProtected();
|
||||
|
||||
VulkanAttachment color = createSwapchainAttachment(swapchain->getCurrentColor());
|
||||
mInfo->attachments = {color};
|
||||
assert_invariant(mInfo->attachments.size() == 0);
|
||||
mInfo->attachments.push_back(color);
|
||||
|
||||
auto& fbkey = mInfo->fbkey;
|
||||
auto& rpkey = mInfo->rpkey;
|
||||
@@ -422,6 +435,11 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
|
||||
mInfo->colors.set(0);
|
||||
}
|
||||
|
||||
void VulkanRenderTarget::releaseSwapchain() {
|
||||
mInfo->colors = {};
|
||||
mInfo->attachments.clear();
|
||||
}
|
||||
|
||||
VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
VulkanContext const& context, fvkmemory::ResourceManager* resourceManager,
|
||||
VmaAllocator allocator, VulkanCommands* commands, uint32_t width, uint32_t height,
|
||||
@@ -675,7 +693,7 @@ void VulkanVertexBuffer::setBuffer(fvkmemory::resource_ptr<VulkanBufferObject> b
|
||||
VulkanBufferObject::VulkanBufferObject(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage)
|
||||
: HwBufferObject(byteCount),
|
||||
: HwBufferObject(byteCount, false),
|
||||
bindingType(bindingType),
|
||||
mBuffer(context, allocator, stagePool, bufferCache, getBufferObjectBinding(bindingType),
|
||||
usage, byteCount) {}
|
||||
|
||||
@@ -245,7 +245,13 @@ struct PushConstantDescription {
|
||||
private:
|
||||
static constexpr uint32_t ENTRY_SIZE = sizeof(uint32_t);
|
||||
|
||||
utils::FixedCapacityVector<backend::ConstantType> mTypes[Program::SHADER_TYPE_COUNT];
|
||||
struct ConstantDescription {
|
||||
utils::FixedCapacityVector<backend::ConstantType> types;
|
||||
uint32_t offset = 0;
|
||||
};
|
||||
|
||||
// Describes the constants in each shader stage.
|
||||
ConstantDescription mDescriptions[Program::SHADER_TYPE_COUNT];
|
||||
VkPushConstantRange mRanges[Program::SHADER_TYPE_COUNT];
|
||||
uint32_t mRangeCount;
|
||||
};
|
||||
@@ -366,7 +372,13 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
|
||||
inline bool isSwapChain() const { return !mOffscreen; }
|
||||
inline bool isProtected() const { return mProtected; }
|
||||
|
||||
void bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain);
|
||||
void bindSwapChain(fvkmemory::resource_ptr<VulkanSwapChain> swapchain);
|
||||
|
||||
void releaseSwapchain();
|
||||
|
||||
bool isSwapchainBound() const {
|
||||
return isSwapChain() && mInfo->colors[0];
|
||||
}
|
||||
|
||||
void emitBarriersBeginRenderPass(VulkanCommandBuffer& commands);
|
||||
|
||||
@@ -470,7 +482,7 @@ struct VulkanIndexBuffer : public HwIndexBuffer, fvkmemory::Resource {
|
||||
VulkanIndexBuffer(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint8_t elementSize,
|
||||
uint32_t indexCount)
|
||||
: HwIndexBuffer(elementSize, indexCount),
|
||||
: HwIndexBuffer(elementSize, indexCount, false),
|
||||
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32),
|
||||
mBuffer(context, allocator, stagePool, bufferCache, VulkanBufferBinding::INDEX,
|
||||
BufferUsage::STATIC, elementSize * indexCount) {}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "VulkanPipelineCache.h"
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
@@ -36,6 +37,8 @@ namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
using utils::JobSystem;
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
void printPipelineFeedbackInfo(VkPipelineCreationFeedbackCreateInfo const& feedbackInfo) {
|
||||
VkPipelineCreationFeedback const& pipelineInfo = *feedbackInfo.pPipelineCreationFeedback;
|
||||
@@ -66,13 +69,26 @@ void printPipelineFeedbackInfo(VkPipelineCreationFeedbackCreateInfo const& feedb
|
||||
|
||||
} // namespace
|
||||
|
||||
VulkanPipelineCache::VulkanPipelineCache(VkDevice device, VulkanContext const& context)
|
||||
VulkanPipelineCache::VulkanPipelineCache(DriverBase& driver, VkDevice device, VulkanContext const& context)
|
||||
: mDevice(device),
|
||||
mCallbackManager(driver),
|
||||
mContext(context) {
|
||||
VkPipelineCacheCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
|
||||
};
|
||||
bluevk::vkCreatePipelineCache(mDevice, &createInfo, VKALLOC, &mPipelineCache);
|
||||
|
||||
if (mContext.shouldUsePipelineCachePrewarming()) {
|
||||
mCompilerThreadPool.init(
|
||||
/*threadCount=*/1,
|
||||
[]() {
|
||||
JobSystem::setThreadName("CompilerThreadPool");
|
||||
// This thread should be lower priority than the main thread.
|
||||
JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
|
||||
}, []() {
|
||||
// No cleanup required.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
|
||||
@@ -87,9 +103,12 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipelin
|
||||
pipeline.lastUsed = mCurrentTime;
|
||||
return &pipeline;
|
||||
}
|
||||
auto ret = createPipeline();
|
||||
ret->lastUsed = mCurrentTime;
|
||||
return ret;
|
||||
PipelineCacheEntry cacheEntry {
|
||||
.handle = createPipeline(mPipelineRequirements),
|
||||
.lastUsed = mCurrentTime,
|
||||
};
|
||||
assert_invariant(cacheEntry.handle != VK_NULL_HANDLE && "Pipeline handle is VK_NULL_HANDLE");
|
||||
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
|
||||
@@ -107,70 +126,144 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
|
||||
assert_invariant(mPipelineRequirements.shaders[0] && "Vertex shader is not bound.");
|
||||
assert_invariant(mPipelineRequirements.layout && "No pipeline layout specified");
|
||||
void VulkanPipelineCache::asyncPrewarmCache(const VulkanProgram& program,
|
||||
VkPipelineLayout layout,
|
||||
StereoscopicType stereoscopicType,
|
||||
uint8_t stereoscopicViewCount, CompilerPriorityQueue priority) {
|
||||
PipelineKey key {
|
||||
.shaders = {
|
||||
program.getVertexShader(),
|
||||
program.getFragmentShader(),
|
||||
},
|
||||
// We're using dynamic rendering, so this should be empty.
|
||||
.renderPass = VK_NULL_HANDLE,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.subpassIndex = 0,
|
||||
// We're using vertex input dynamic state, so these should be empty.
|
||||
.vertexAttributes = {},
|
||||
.vertexBuffers = {},
|
||||
// Create a reasonable default raster state; we're assuming this is not cached.
|
||||
.rasterState = {
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.blendEnable = VK_FALSE,
|
||||
.depthWriteEnable = VK_FALSE,
|
||||
.alphaToCoverageEnable = VK_FALSE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.colorWriteMask = 0,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.depthClamp = VK_FALSE,
|
||||
.colorTargetCount = 1,
|
||||
.colorBlendOp = BlendEquation::SUBTRACT,
|
||||
.alphaBlendOp = BlendEquation::SUBTRACT,
|
||||
.depthCompareOp = SamplerCompareFunc::L,
|
||||
.depthBiasConstantFactor = 0.f,
|
||||
.depthBiasSlopeFactor = 0.f,
|
||||
},
|
||||
.layout = layout,
|
||||
};
|
||||
PipelineDynamicOptions dynamicOptions {
|
||||
.useDynamicVertexInputState = true,
|
||||
.useDynamicRenderPasses = true,
|
||||
.stereoscopicType = stereoscopicType,
|
||||
.stereoscopicViewCount = stereoscopicViewCount,
|
||||
};
|
||||
|
||||
CallbackManager::Handle cmh = mCallbackManager.get();
|
||||
auto token = std::make_shared<ProgramToken>();
|
||||
mCompilerThreadPool.queue(priority, token, [this, key, dynamicOptions, cmh]() mutable {
|
||||
VkPipeline pipeline = createPipeline(key, dynamicOptions);
|
||||
mCallbackManager.put(cmh);
|
||||
// We don't actually need this pipeline, we just wanted to force the driver to cache
|
||||
// the pipeline's information.
|
||||
if (pipeline != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
|
||||
} else {
|
||||
FVK_LOGW << "Failed to create a pipeline during prewarming, draw-time pipeline "
|
||||
"creation may fail.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
VkPipeline VulkanPipelineCache::createPipeline(
|
||||
const PipelineKey& key, const PipelineDynamicOptions& dynamicOptions) noexcept {
|
||||
assert_invariant(key.shaders[0] && "Vertex shader is not bound.");
|
||||
assert_invariant(key.layout && "No pipeline layout specified");
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[SHADER_MODULE_COUNT];
|
||||
shaderStages[0] = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = mPipelineRequirements.shaders[0],
|
||||
.module = key.shaders[0],
|
||||
.pName = "main",
|
||||
};
|
||||
shaderStages[1] = shaderStages[0];
|
||||
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shaderStages[1].module = mPipelineRequirements.shaders[1];
|
||||
shaderStages[1].module = key.shaders[1];
|
||||
|
||||
bool const hasFragmentShader = shaderStages[1].module != VK_NULL_HANDLE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
||||
VkPipelineColorBlendStateCreateInfo colorBlendState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.attachmentCount = mPipelineRequirements.rasterState.colorTargetCount,
|
||||
.attachmentCount = key.rasterState.colorTargetCount,
|
||||
.pAttachments = colorBlendAttachments,
|
||||
};
|
||||
|
||||
// Expand our size-optimized structs into the proper Vk structs.
|
||||
uint32_t numVertexAttribs = 0;
|
||||
uint32_t numVertexBuffers = 0;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputState;
|
||||
VkVertexInputAttributeDescription vertexAttributes[VERTEX_ATTRIBUTE_COUNT];
|
||||
VkVertexInputBindingDescription vertexBuffers[VERTEX_ATTRIBUTE_COUNT];
|
||||
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
|
||||
if (mPipelineRequirements.vertexAttributes[i].format > 0) {
|
||||
vertexAttributes[numVertexAttribs++] = mPipelineRequirements.vertexAttributes[i];
|
||||
}
|
||||
if (mPipelineRequirements.vertexBuffers[i].stride > 0) {
|
||||
vertexBuffers[numVertexBuffers++] = mPipelineRequirements.vertexBuffers[i];
|
||||
if (!dynamicOptions.useDynamicVertexInputState) {
|
||||
uint32_t numVertexAttribs = 0;
|
||||
uint32_t numVertexBuffers = 0;
|
||||
|
||||
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
|
||||
if (key.vertexAttributes[i].format > 0) {
|
||||
vertexAttributes[numVertexAttribs++] = key.vertexAttributes[i];
|
||||
}
|
||||
if (key.vertexBuffers[i].stride > 0) {
|
||||
vertexBuffers[numVertexBuffers++] = key.vertexBuffers[i];
|
||||
}
|
||||
}
|
||||
vertexInputState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = numVertexBuffers,
|
||||
.pVertexBindingDescriptions = vertexBuffers,
|
||||
.vertexAttributeDescriptionCount = numVertexAttribs,
|
||||
.pVertexAttributeDescriptions = vertexAttributes,
|
||||
};
|
||||
}
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = numVertexBuffers,
|
||||
.pVertexBindingDescriptions = vertexBuffers,
|
||||
.vertexAttributeDescriptionCount = numVertexAttribs,
|
||||
.pVertexAttributeDescriptions = vertexAttributes,
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = (VkPrimitiveTopology) mPipelineRequirements.topology,
|
||||
.topology = (VkPrimitiveTopology) key.topology,
|
||||
};
|
||||
VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1,
|
||||
};
|
||||
VkDynamicState dynamicStateEnables[] = {
|
||||
|
||||
constexpr size_t maxDynamicStates = 3;
|
||||
size_t numDynamicStates = 2;
|
||||
VkDynamicState enabledDynamicStates[maxDynamicStates] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
if (dynamicOptions.useDynamicVertexInputState) {
|
||||
enabledDynamicStates[numDynamicStates++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT;
|
||||
}
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dynamicStateEnables,
|
||||
.dynamicStateCount = static_cast<uint32_t>(numDynamicStates),
|
||||
.pDynamicStates = enabledDynamicStates,
|
||||
};
|
||||
auto const& raster = mPipelineRequirements.rasterState;
|
||||
|
||||
auto const& raster = key.rasterState;
|
||||
VkPipelineRasterizationStateCreateInfo vkRaster = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = raster.depthClamp,
|
||||
@@ -218,7 +311,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = hasFragmentShader ? SHADER_MODULE_COUNT : 1,
|
||||
.pStages = shaderStages,
|
||||
.pVertexInputState = &vertexInputState,
|
||||
.pVertexInputState = dynamicOptions.useDynamicVertexInputState ? nullptr : &vertexInputState,
|
||||
.pInputAssemblyState = &inputAssemblyState,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &vkRaster,
|
||||
@@ -226,9 +319,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
.pDepthStencilState = &vkDs,
|
||||
.pColorBlendState = &colorBlendState,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = mPipelineRequirements.layout,
|
||||
.renderPass = mPipelineRequirements.renderPass,
|
||||
.subpass = mPipelineRequirements.subpassIndex,
|
||||
.layout = key.layout,
|
||||
.renderPass = key.renderPass,
|
||||
.subpass = key.subpassIndex,
|
||||
};
|
||||
|
||||
// There are no color attachments if there is no bound fragment shader. (e.g. shadow map gen)
|
||||
@@ -252,6 +345,27 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
}
|
||||
}
|
||||
|
||||
VkPipelineRenderingCreateInfoKHR renderingInfo {};
|
||||
VkFormat pipelineRenderingColorFormats[] = {VK_FORMAT_UNDEFINED};
|
||||
if (dynamicOptions.useDynamicRenderPasses) {
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
|
||||
renderingInfo.pNext = pipelineCreateInfo.pNext;
|
||||
// Fill values in with empty values where we do not already have values.
|
||||
renderingInfo.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
|
||||
renderingInfo.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
|
||||
// If multiview, create a bitmask with bits representing each enabled view set to 1;
|
||||
// otherwise, set the view mask to 0.
|
||||
renderingInfo.viewMask = dynamicOptions.stereoscopicType == StereoscopicType::MULTIVIEW ?
|
||||
(1 << dynamicOptions.stereoscopicViewCount) - 1 : 0;
|
||||
|
||||
if (hasFragmentShader) {
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachmentFormats = pipelineRenderingColorFormats;
|
||||
}
|
||||
|
||||
pipelineCreateInfo.pNext = &renderingInfo;
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
|
||||
<< shaderStages[1].module << ")";
|
||||
@@ -271,11 +385,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
pipelineCreateInfo.pNext = &feedbackInfo;
|
||||
}
|
||||
#endif
|
||||
PipelineCacheEntry cacheEntry = {
|
||||
.lastUsed = mCurrentTime,
|
||||
};
|
||||
VkPipeline pipeline;
|
||||
VkResult error = vkCreateGraphicsPipelines(mDevice, mPipelineCache, 1, &pipelineCreateInfo,
|
||||
VKALLOC, &cacheEntry.handle);
|
||||
VKALLOC, &pipeline);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
|
||||
@@ -289,9 +401,9 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
assert_invariant(error == VK_SUCCESS);
|
||||
if (error != VK_SUCCESS) {
|
||||
FVK_LOGE << "vkCreateGraphicsPipelines error " << error;
|
||||
return nullptr;
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept {
|
||||
@@ -334,6 +446,14 @@ void VulkanPipelineCache::bindVertexArray(VkVertexInputAttributeDescription cons
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::addCachePrewarmCallback(CallbackHandler* handler,
|
||||
const CallbackHandler::Callback callback,
|
||||
void* user) {
|
||||
if (callback) {
|
||||
mCallbackManager.setCallback(handler, callback, user);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::resetBoundPipeline() {
|
||||
mBoundPipeline = {};
|
||||
}
|
||||
@@ -345,6 +465,9 @@ void VulkanPipelineCache::terminate() noexcept {
|
||||
mPipelines.clear();
|
||||
resetBoundPipeline();
|
||||
|
||||
mCallbackManager.terminate();
|
||||
mCompilerThreadPool.terminate();
|
||||
|
||||
vkDestroyPipelineCache(mDevice, mPipelineCache, VKALLOC);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
|
||||
|
||||
#include "CallbackManager.h"
|
||||
#include "CompilerThreadPool.h"
|
||||
#include "VulkanCommands.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -86,14 +88,38 @@ public:
|
||||
|
||||
static_assert(sizeof(RasterState) == 16, "RasterState must not have implicit padding.");
|
||||
|
||||
VulkanPipelineCache(VkDevice device, VulkanContext const& context);
|
||||
/**
|
||||
* Creates a new instance of a pipeline cache for graphics pipelines.
|
||||
*
|
||||
* @param driver The driver this is being instantiated for. This is used only for construction of
|
||||
* the callback manager, which references the driver for scheduling callbacks.
|
||||
* @param device The device that the pipelines will be created and run on.
|
||||
* @param context Information about the current instance of Vulkan, such as supported extensions,
|
||||
* and enabled features.
|
||||
*/
|
||||
VulkanPipelineCache(DriverBase& driver, VkDevice device, VulkanContext const& context);
|
||||
|
||||
void bindLayout(VkPipelineLayout layout) noexcept;
|
||||
// Loads a fake pipeline into memory on a separate thread, with the intent of
|
||||
// preloading the Vulkan cache with enough information to have a cache hit when
|
||||
// compiling the pipeline on the main thread at draw time. This is very dependent
|
||||
// on the implementation of the driver on the current device; it's expected to work
|
||||
// on devices with VK_EXT_vertex_input_dynamic_state and VK_KHR_dynamic_rendering.
|
||||
void asyncPrewarmCache(const VulkanProgram& program, VkPipelineLayout layout,
|
||||
StereoscopicType stereoscopicType, uint8_t stereoscopicViewCount,
|
||||
CompilerPriorityQueue priority);
|
||||
|
||||
// Notifies the callback once all in-flight async cache prewarm jobs are complete.
|
||||
// This typically signals that it is safe to use a material at draw time without
|
||||
// hitching.
|
||||
void addCachePrewarmCallback(CallbackHandler* handler,
|
||||
const CallbackHandler::Callback callback,
|
||||
void* user);
|
||||
|
||||
// Creates a new pipeline if necessary and binds it using vkCmdBindPipeline.
|
||||
void bindPipeline(VulkanCommandBuffer* commands);
|
||||
|
||||
// Each of the following methods are fast and do not make Vulkan calls.
|
||||
void bindLayout(VkPipelineLayout layout) noexcept;
|
||||
void bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept;
|
||||
void bindRasterState(RasterState const& rasterState) noexcept;
|
||||
void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept;
|
||||
@@ -164,6 +190,19 @@ private:
|
||||
VkPipelineLayout layout; // 8 : 304
|
||||
};
|
||||
|
||||
// Provides information about any dynamic state that should be used in creation of the
|
||||
// pipeline (if supported).
|
||||
struct PipelineDynamicOptions {
|
||||
// Requires `VK_EXT_vertex_input_dynamic_state` to enable.
|
||||
bool useDynamicVertexInputState = false;
|
||||
// Requires `VK_KHR_dynamic_rendering` to enable.
|
||||
bool useDynamicRenderPasses = false;
|
||||
// Only used if `useDynamicRenderPasses` is true.
|
||||
StereoscopicType stereoscopicType = StereoscopicType::NONE;
|
||||
// Only used if `stereoscopicType` is `StereoscopicType::MULTIVIEW`.
|
||||
uint8_t stereoscopicViewCount = 2;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PipelineKey) == 312, "PipelineKey must not have implicit padding.");
|
||||
|
||||
using PipelineHashFn = utils::hash::MurmurHashFn<PipelineKey>;
|
||||
@@ -195,8 +234,15 @@ private:
|
||||
|
||||
PipelineMap mPipelines;
|
||||
|
||||
// Creates a pipeline, with all optional dynamic pipeline states diabled.
|
||||
// Note - because PipelineDynamicOptions is defined within VulkanPipelineCache,
|
||||
// we cannot define the function with a default arg for it explicitly.
|
||||
inline VkPipeline createPipeline(const PipelineKey& key) noexcept {
|
||||
return createPipeline(key, {});
|
||||
}
|
||||
|
||||
// These helpers all return unstable pointers that should not be stored.
|
||||
PipelineCacheEntry* createPipeline() noexcept;
|
||||
VkPipeline createPipeline(const PipelineKey& key, const PipelineDynamicOptions& dynamicOptions) noexcept;
|
||||
|
||||
// Immutable state.
|
||||
VkDevice mDevice = VK_NULL_HANDLE;
|
||||
@@ -211,6 +257,14 @@ private:
|
||||
// Current bindings for the pipeline and descriptor sets.
|
||||
PipelineKey mBoundPipeline = {};
|
||||
|
||||
// Thread pool that allows us to "prewarm" the pipeline cache, reducing draw-time
|
||||
// pipeline compilation time.
|
||||
CompilerThreadPool mCompilerThreadPool;
|
||||
|
||||
// Callback manager that allows us to notify the frontend when a set of pipelines have
|
||||
// been prewarmed, signifying that it is safe to compile pipelines at draw time.
|
||||
CallbackManager mCallbackManager;
|
||||
|
||||
[[maybe_unused]] VulkanContext const& mContext;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
||||
|
||||
// build the push constant layout key
|
||||
uint32_t const pushConstantRangeCount = program->getPushConstantRangeCount();
|
||||
auto const& pushConstantRanges = program->getPushConstantRanges();
|
||||
auto pushConstantRanges = program->getPushConstantRanges();
|
||||
if (pushConstantRangeCount > 0) {
|
||||
assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT);
|
||||
for (uint8_t i = 0; i < pushConstantRangeCount; ++i) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user