Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3308ec7e34 |
+10
-2
@@ -1,7 +1,15 @@
|
|||||||
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||||
;;; For more information see (info "(emacs) Directory Variables")
|
;;; For more information see (info "(emacs) Directory Variables")
|
||||||
|
|
||||||
((c++-mode . ((c-file-style . "filament")
|
((c++-mode . ((eval . (progn
|
||||||
|
(make-local-variable 'eglot-ignored-server-capabilities)
|
||||||
|
(add-to-list 'eglot-ignored-server-capabilities
|
||||||
|
:documentOnTypeFormattingProvider)))
|
||||||
|
(c-file-style . "filament")
|
||||||
(apheleia-inhibit . t)))
|
(apheleia-inhibit . t)))
|
||||||
(c-mode . ((c-file-style . "filament")
|
(c-mode . ((eval . (progn
|
||||||
|
(make-local-variable 'eglot-ignored-server-capabilities)
|
||||||
|
(add-to-list 'eglot-ignored-server-capabilities
|
||||||
|
:documentOnTypeFormattingProvider)))
|
||||||
|
(c-file-style . "filament")
|
||||||
(apheleia-inhibit . t))))
|
(apheleia-inhibit . t))))
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ end_of_line = lf
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
[*.{c,cpp,h,inc,kt,java,js,md}]
|
[*.{c,cpp,h,inc,kt,java,js,md,fs,vs}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
max_line_length = 100
|
max_line_length = 100
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
name: build-android
|
name: build-android
|
||||||
# We intentially use a larger runner here to enable larger disk space
|
# We intentially use a larger runner here to enable larger disk space
|
||||||
# (standard linux runner will fail on disk space and faster build time).
|
# (standard linux runner will fail on disk space and faster build time).
|
||||||
runs-on: 'ubuntu-24.04-32core'
|
runs-on: ubuntu-22.04-32core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-linux:
|
build-linux:
|
||||||
name: build-linux
|
name: build-linux
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||||
@@ -42,12 +40,10 @@ jobs:
|
|||||||
|
|
||||||
build-android:
|
build-android:
|
||||||
name: build-android
|
name: build-android
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
@@ -64,8 +60,6 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/ios && printf "y" | ./build.sh presubmit
|
cd build/ios && printf "y" | ./build.sh presubmit
|
||||||
@@ -75,7 +69,7 @@ jobs:
|
|||||||
|
|
||||||
build-web:
|
build-web:
|
||||||
name: build-web
|
name: build-web
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
@@ -85,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
validate-docs:
|
validate-docs:
|
||||||
name: validate-docs
|
name: validate-docs
|
||||||
runs-on: 'ubuntu-24.04-4core'
|
runs-on: ubuntu-22.04-4core
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
with:
|
with:
|
||||||
@@ -98,73 +92,26 @@ jobs:
|
|||||||
|
|
||||||
test-renderdiff:
|
test-renderdiff:
|
||||||
name: test-renderdiff
|
name: test-renderdiff
|
||||||
runs-on: macos-14-xlarge
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
- name: Set up Homebrew
|
- uses: ./.github/actions/ubuntu-apt-add-src
|
||||||
id: set-up-homebrew
|
- name: Run script
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Cache Mesa and deps
|
|
||||||
id: mesa-cache
|
|
||||||
uses: actions/cache@v4 # Use a specific version
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
$HOME/Library/Caches/Homebrew
|
|
||||||
mesa
|
|
||||||
key: ${{ runner.os }}-mesa-deps-${{ vars.MESA_VERSION }}
|
|
||||||
- name: Get Mesa
|
|
||||||
id: mesa-prereq
|
|
||||||
env:
|
|
||||||
MESA_VERSION: ${{ vars.MESA_VERSION }}
|
|
||||||
run: |
|
run: |
|
||||||
bash test/utils/get_mesa.sh
|
source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh
|
||||||
- name: Run Test
|
|
||||||
run: |
|
|
||||||
bash test/renderdiff/test.sh
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: presubmit-renderdiff-result
|
name: presubmit-renderdiff-result
|
||||||
path: ./out/renderdiff_tests
|
path: ./out/renderdiff_tests
|
||||||
|
|
||||||
validate-wgsl-webgpu:
|
validate-wgsl-pipeline:
|
||||||
name: validate-wgsl-webgpu
|
name: validate-wgsl-pipeline
|
||||||
runs-on: 'ubuntu-24.04-8core'
|
runs-on: macos-14-xlarge
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
run: ./build.sh -W debug test_filamat
|
||||||
- name: Run test
|
- name: Run test
|
||||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||||
|
|
||||||
code-correcteness:
|
|
||||||
name: code-correctness
|
|
||||||
runs-on: 'macos-14-xlarge'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4.1.6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up Homebrew
|
|
||||||
id: set-up-homebrew
|
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install prerequisites
|
|
||||||
run: |
|
|
||||||
pip install pyyaml
|
|
||||||
brew install llvm
|
|
||||||
sudo ln -s "$(brew --prefix llvm)/bin/clang-tidy" "/usr/local/bin/clang-tidy"
|
|
||||||
- name: Run build script
|
|
||||||
# We need to build before clang-tidy can run analysis
|
|
||||||
run: |
|
|
||||||
# This will build for all three desktop backends on mac
|
|
||||||
./build.sh -p desktop debug gltf_viewer
|
|
||||||
- name: Run test
|
|
||||||
run: |
|
|
||||||
bash test/code-correctness/test.sh
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
|
|
||||||
build-web:
|
build-web:
|
||||||
name: build-web
|
name: build-web
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -103,7 +103,7 @@ jobs:
|
|||||||
|
|
||||||
build-android:
|
build-android:
|
||||||
name: build-android
|
name: build-android
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
|
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-web:
|
build-web:
|
||||||
name: build-web
|
name: build-web
|
||||||
runs-on: 'ubuntu-24.04-16core'
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
|||||||
-15
@@ -18,18 +18,3 @@ test*.json
|
|||||||
results
|
results
|
||||||
/compile_commands.json
|
/compile_commands.json
|
||||||
/.cache
|
/.cache
|
||||||
build/.cmake/
|
|
||||||
build/CMakeCache.txt
|
|
||||||
build/CMakeFiles/
|
|
||||||
build/Makefile
|
|
||||||
build/SPIRV-Tools*
|
|
||||||
build/cmake_install.cmake
|
|
||||||
build/compile_commands.json
|
|
||||||
build/filament/
|
|
||||||
build/include/
|
|
||||||
build/libs/
|
|
||||||
build/mac/ninja
|
|
||||||
build/samples/
|
|
||||||
build/shaders/
|
|
||||||
build/third_party/
|
|
||||||
build/tools/
|
|
||||||
|
|||||||
+3
-21
@@ -139,14 +139,14 @@ else()
|
|||||||
set(LINUX FALSE)
|
set(LINUX FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT FILAMENT_OSMESA_PATH STREQUAL "")
|
if (LINUX)
|
||||||
|
if (NOT FILAMENT_OSMESA_PATH STREQUAL "")
|
||||||
if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/)
|
if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/)
|
||||||
message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}")
|
message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}")
|
||||||
endif()
|
endif()
|
||||||
set(FILAMENT_SUPPORTS_OSMESA TRUE)
|
set(FILAMENT_SUPPORTS_OSMESA TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LINUX)
|
|
||||||
if (FILAMENT_SUPPORTS_WAYLAND)
|
if (FILAMENT_SUPPORTS_WAYLAND)
|
||||||
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
|
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
|
||||||
set(FILAMENT_SUPPORTS_X11 FALSE)
|
set(FILAMENT_SUPPORTS_X11 FALSE)
|
||||||
@@ -184,12 +184,6 @@ if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE)
|
|||||||
set(IS_HOST_PLATFORM TRUE)
|
set(IS_HOST_PLATFORM TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
|
||||||
add_definitions(-DFILAMENT_SUPPORTS_OSMESA)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
||||||
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
||||||
@@ -334,9 +328,6 @@ if (MSVC)
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} /W0 /Zc:__cplusplus")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} /W0 /Zc:__cplusplus")
|
||||||
else()
|
else()
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} -fstrict-aliasing -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} -fstrict-aliasing -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations")
|
||||||
if (APPLE)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nullability-extension")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_USE_EXTERNAL_GLES3)
|
if (FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
@@ -610,14 +601,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# With WebGPU, push constants are not supported. Skinning uses them.
|
|
||||||
# WebGPU has a proposal to add push constants at https://github.com/gpuweb/gpuweb/blob/main/proposals/push-constants.md
|
|
||||||
# With WebGPU, Tint does not support ClipDistance which is used in Stereo. Mentioned in comment
|
|
||||||
# https://github.com/google/dawn/blob/855d17b08abdf02f9142bf5a8f14d0ea088810a4/src/tint/lang/spirv/reader/ast_parser/function.cc#L4434
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=skinning,stereo)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Disable ESSL 1.0 code generation.
|
# Disable ESSL 1.0 code generation.
|
||||||
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
||||||
@@ -801,7 +784,6 @@ add_subdirectory(${EXTERNAL}/draco/tnt)
|
|||||||
add_subdirectory(${EXTERNAL}/jsmn/tnt)
|
add_subdirectory(${EXTERNAL}/jsmn/tnt)
|
||||||
add_subdirectory(${EXTERNAL}/stb/tnt)
|
add_subdirectory(${EXTERNAL}/stb/tnt)
|
||||||
add_subdirectory(${EXTERNAL}/getopt)
|
add_subdirectory(${EXTERNAL}/getopt)
|
||||||
add_subdirectory(${EXTERNAL}/perfetto/tnt)
|
|
||||||
|
|
||||||
# Note that this has to be placed after mikktspace in order for combine_static_libs to work.
|
# Note that this has to be placed after mikktspace in order for combine_static_libs to work.
|
||||||
add_subdirectory(${LIBRARIES}/geometry)
|
add_subdirectory(${LIBRARIES}/geometry)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.59.3'
|
implementation 'com.google.android.filament:filament-android:1.58.0'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
|||||||
iOS projects can use CocoaPods to install the latest release:
|
iOS projects can use CocoaPods to install the latest release:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pod 'Filament', '~> 1.59.3'
|
pod 'Filament', '~> 1.58.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -7,27 +7,6 @@ A new header is inserted each time a *tag* is created.
|
|||||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||||
|
|
||||||
## v1.59.4
|
|
||||||
|
|
||||||
|
|
||||||
## v1.59.3
|
|
||||||
|
|
||||||
|
|
||||||
## v1.59.2
|
|
||||||
|
|
||||||
- Fix build/compile errors when upgrading to MacOS 15.4
|
|
||||||
|
|
||||||
## v1.59.1
|
|
||||||
|
|
||||||
|
|
||||||
## v1.59.0
|
|
||||||
|
|
||||||
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
|
|
||||||
|
|
||||||
## v1.58.2
|
|
||||||
|
|
||||||
- engine: Generate 1D instead of 3D LUTs for color grading whenever possible.
|
|
||||||
|
|
||||||
## v1.58.1
|
## v1.58.1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -142,12 +142,6 @@ abstract class MaterialCompiler extends TaskWithBinary {
|
|||||||
if (!exclude_vulkan) {
|
if (!exclude_vulkan) {
|
||||||
matcArgs += ['-a', 'vulkan']
|
matcArgs += ['-a', 'vulkan']
|
||||||
}
|
}
|
||||||
def include_webgpu = providers
|
|
||||||
.gradleProperty("com.google.android.filament.include-webgpu")
|
|
||||||
.forUseAtConfigurationTime().present
|
|
||||||
if (include_webgpu) {
|
|
||||||
matcArgs += ['-a', 'webgpu', '--variant-filter=skinning,stereo']
|
|
||||||
}
|
|
||||||
|
|
||||||
def mat_no_opt = providers
|
def mat_no_opt = providers
|
||||||
.gradleProperty("com.google.android.filament.matnopt")
|
.gradleProperty("com.google.android.filament.matnopt")
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||||
# See third_party/dawn/tnt/CMakeLists.txt and libs/filamat/CMakeLists.txt
|
add_library(webgpu_dawn STATIC IMPORTED)
|
||||||
add_library(tint STATIC IMPORTED)
|
set_target_properties(webgpu_dawn PROPERTIES IMPORTED_LOCATION
|
||||||
set_target_properties(tint PROPERTIES IMPORTED_LOCATION
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebgpu_dawn.a)
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libtint_combined.a)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
||||||
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
||||||
@@ -26,10 +26,6 @@ add_library(utils STATIC IMPORTED)
|
|||||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||||
|
|
||||||
add_library(perfetto STATIC IMPORTED)
|
|
||||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
|
||||||
|
|
||||||
add_library(filabridge STATIC IMPORTED)
|
add_library(filabridge STATIC IMPORTED)
|
||||||
set_target_properties(filabridge PROPERTIES IMPORTED_LOCATION
|
set_target_properties(filabridge PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilabridge.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilabridge.a)
|
||||||
@@ -44,7 +40,6 @@ set_target_properties(shaders PROPERTIES IMPORTED_LOCATION
|
|||||||
|
|
||||||
set(FILAMAT_INCLUDE_DIRS
|
set(FILAMAT_INCLUDE_DIRS
|
||||||
../../libs/utils/include
|
../../libs/utils/include
|
||||||
../../third_party/perfetto
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(${FILAMENT_DIR}/include)
|
include_directories(${FILAMENT_DIR}/include)
|
||||||
@@ -60,8 +55,7 @@ target_link_libraries(filamat-jni
|
|||||||
filabridge
|
filabridge
|
||||||
shaders
|
shaders
|
||||||
utils
|
utils
|
||||||
perfetto
|
|
||||||
log
|
log
|
||||||
smol-v
|
smol-v
|
||||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:tint>
|
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn> # for tint
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ add_library(utils STATIC IMPORTED)
|
|||||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||||
|
|
||||||
add_library(perfetto STATIC IMPORTED)
|
|
||||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
|
||||||
|
|
||||||
add_library(ibl-lite STATIC IMPORTED)
|
add_library(ibl-lite STATIC IMPORTED)
|
||||||
set_target_properties(ibl-lite PROPERTIES IMPORTED_LOCATION
|
set_target_properties(ibl-lite PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libibl-lite.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libibl-lite.a)
|
||||||
@@ -33,6 +29,10 @@ add_library(filaflat STATIC IMPORTED)
|
|||||||
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
||||||
|
|
||||||
|
add_library(filamat STATIC IMPORTED)
|
||||||
|
set_target_properties(filamat PROPERTIES IMPORTED_LOCATION
|
||||||
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilamat.a)
|
||||||
|
|
||||||
add_library(geometry STATIC IMPORTED)
|
add_library(geometry STATIC IMPORTED)
|
||||||
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
||||||
@@ -59,11 +59,11 @@ add_library(smol-v STATIC IMPORTED)
|
|||||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||||
|
|
||||||
if (FILAMENT_ENABLE_FGVIEWER)
|
if (FILAMENT_ENABLE_FGVIEWER)
|
||||||
add_library(fgviewer STATIC IMPORTED)
|
add_library(fgviewer STATIC IMPORTED)
|
||||||
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_ENABLE_MATDBG)
|
if (FILAMENT_ENABLE_MATDBG)
|
||||||
add_library(matdbg STATIC IMPORTED)
|
add_library(matdbg STATIC IMPORTED)
|
||||||
@@ -127,7 +127,6 @@ target_link_libraries(filament-jni
|
|||||||
PRIVATE android
|
PRIVATE android
|
||||||
PRIVATE jnigraphics
|
PRIVATE jnigraphics
|
||||||
PRIVATE utils
|
PRIVATE utils
|
||||||
PRIVATE perfetto
|
|
||||||
|
|
||||||
# libgeometry is PUBLIC because gltfio uses it.
|
# libgeometry is PUBLIC because gltfio uses it.
|
||||||
PUBLIC geometry
|
PUBLIC geometry
|
||||||
@@ -146,7 +145,6 @@ target_include_directories(filament-jni PRIVATE
|
|||||||
${FILAMENT_DIR}/include
|
${FILAMENT_DIR}/include
|
||||||
../../filament/backend/include
|
../../filament/backend/include
|
||||||
../../third_party/robin-map
|
../../third_party/robin-map
|
||||||
../../third_party/perfetto
|
|
||||||
../../libs/utils/include)
|
../../libs/utils/include)
|
||||||
|
|
||||||
# Force a relink when the version script is changed:
|
# Force a relink when the version script is changed:
|
||||||
|
|||||||
@@ -68,21 +68,6 @@ Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jcl
|
|||||||
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
|
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
|
||||||
Java_com_google_android_filament_Texture_nGetMaxTextureSize(JNIEnv *, jclass,
|
|
||||||
jlong nativeEngine, jint sampler) {
|
|
||||||
Engine *engine = (Engine *) nativeEngine;
|
|
||||||
return Texture::getMaxTextureSize(*engine, (Texture::Sampler)sampler);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
|
||||||
Java_com_google_android_filament_Texture_nGetMaxArrayTextureLayers(JNIEnv *, jclass,
|
|
||||||
jlong nativeEngine) {
|
|
||||||
Engine *engine = (Engine *) nativeEngine;
|
|
||||||
return Texture::getMaxArrayTextureLayers(*engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jboolean JNICALL
|
extern "C" JNIEXPORT jboolean JNICALL
|
||||||
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
|
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
|
||||||
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
|
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
|
||||||
|
|||||||
+4
-10
@@ -46,8 +46,9 @@ import static com.google.android.filament.Asserts.assertFloat4In;
|
|||||||
*
|
*
|
||||||
* <h1>Performance</h1>
|
* <h1>Performance</h1>
|
||||||
*
|
*
|
||||||
* Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may
|
* Creating a new ColorGrading object may be more expensive than other Filament objects as a
|
||||||
* need to be generated. The generation of this LUT, if necessary, may happen on the CPU.
|
* 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on
|
||||||
|
* the CPU.
|
||||||
*
|
*
|
||||||
* <h1>Ordering</h1>
|
* <h1>Ordering</h1>
|
||||||
*
|
*
|
||||||
@@ -159,10 +160,6 @@ public class ColorGrading {
|
|||||||
* quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit
|
* quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit
|
||||||
* LUT, and a ultra quality will use a 64x64x64 16 bit LUT.
|
* LUT, and a ultra quality will use a 64x64x64 16 bit LUT.
|
||||||
*
|
*
|
||||||
* This setting has no effect if generating a 1D LUT.
|
|
||||||
*
|
|
||||||
* This overrides the values set by format() and dimensions().
|
|
||||||
*
|
|
||||||
* The default quality is {@link QualityLevel#MEDIUM}.
|
* The default quality is {@link QualityLevel#MEDIUM}.
|
||||||
*
|
*
|
||||||
* @param qualityLevel The desired quality of the color grading process
|
* @param qualityLevel The desired quality of the color grading process
|
||||||
@@ -178,8 +175,6 @@ public class ColorGrading {
|
|||||||
* When color grading is implemented using a 3D LUT, this sets the texture format of
|
* When color grading is implemented using a 3D LUT, this sets the texture format of
|
||||||
* of the LUT. This overrides the value set by quality().
|
* of the LUT. This overrides the value set by quality().
|
||||||
*
|
*
|
||||||
* This setting has no effect if generating a 1D LUT.
|
|
||||||
*
|
|
||||||
* The default is INTEGER
|
* The default is INTEGER
|
||||||
*
|
*
|
||||||
* @param format The desired format of the 3D LUT.
|
* @param format The desired format of the 3D LUT.
|
||||||
@@ -195,8 +190,6 @@ public class ColorGrading {
|
|||||||
* When color grading is implemented using a 3D LUT, this sets the dimension of the LUT.
|
* When color grading is implemented using a 3D LUT, this sets the dimension of the LUT.
|
||||||
* This overrides the value set by quality().
|
* This overrides the value set by quality().
|
||||||
*
|
*
|
||||||
* This setting has no effect if generating a 1D LUT.
|
|
||||||
*
|
|
||||||
* The default is 32
|
* The default is 32
|
||||||
*
|
*
|
||||||
* @param dim The desired dimension of the LUT. Between 16 and 64.
|
* @param dim The desired dimension of the LUT. Between 16 and 64.
|
||||||
@@ -623,3 +616,4 @@ public class ColorGrading {
|
|||||||
|
|
||||||
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
|
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -691,24 +691,6 @@ public class Texture {
|
|||||||
pixelDataType.ordinal());
|
pixelDataType.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param engine {@link Engine}
|
|
||||||
* @param type Texture sampler type
|
|
||||||
* @return The maximum size in texels of a texture of type \p type. At least 2048 for
|
|
||||||
* 2D textures, 256 for 3D textures
|
|
||||||
*/
|
|
||||||
public static int getMaxTextureSize(@NonNull Engine engine, Sampler type) {
|
|
||||||
return nGetMaxTextureSize(engine.getNativeObject(), type.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param engine {@link Engine}
|
|
||||||
* @return The maximum number of layers supported by texture arrays. At least 256.
|
|
||||||
*/
|
|
||||||
public static int getMaxArrayTextureLayers(@NonNull Engine engine) {
|
|
||||||
return nGetMaxArrayTextureLayers(engine.getNativeObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
||||||
*/
|
*/
|
||||||
@@ -1307,8 +1289,6 @@ public class Texture {
|
|||||||
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
|
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
|
||||||
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
|
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
|
||||||
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
|
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
|
||||||
private static native int nGetMaxTextureSize(long nativeObject, int ordinal);
|
|
||||||
private static native int nGetMaxArrayTextureLayers(long nativeObject);
|
|
||||||
|
|
||||||
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
|
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
|
||||||
int pixelDataType);
|
int pixelDataType);
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ package com.google.android.filament;
|
|||||||
* <li>DisplayRangeToneMapper</li>
|
* <li>DisplayRangeToneMapper</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* You can create custom tone mapping operators by subclassing ToneMapper.
|
||||||
*/
|
*/
|
||||||
public class ToneMapper {
|
public class ToneMapper {
|
||||||
private final long mNativeObject;
|
private final long mNativeObject;
|
||||||
|
|||||||
@@ -35,10 +35,6 @@ add_library(utils STATIC IMPORTED)
|
|||||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||||
|
|
||||||
add_library(perfetto STATIC IMPORTED)
|
|
||||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
|
||||||
|
|
||||||
add_library(uberzlib STATIC IMPORTED)
|
add_library(uberzlib STATIC IMPORTED)
|
||||||
set_target_properties(uberzlib PROPERTIES IMPORTED_LOCATION
|
set_target_properties(uberzlib PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberzlib.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberzlib.a)
|
||||||
@@ -125,7 +121,6 @@ set(GLTFIO_INCLUDE_DIRS
|
|||||||
../../third_party/meshoptimizer/src
|
../../third_party/meshoptimizer/src
|
||||||
../../third_party/robin-map
|
../../third_party/robin-map
|
||||||
../../third_party/stb
|
../../third_party/stb
|
||||||
../../third_party/perfetto
|
|
||||||
../../libs/utils/include
|
../../libs/utils/include
|
||||||
../../libs/ktxreader/include
|
../../libs/ktxreader/include
|
||||||
)
|
)
|
||||||
@@ -134,7 +129,7 @@ add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
|
|||||||
target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
|
target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
|
||||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
|
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
|
||||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
|
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
|
||||||
target_link_libraries(gltfio-jni filament-jni utils perfetto uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
|
target_link_libraries(gltfio-jni filament-jni utils uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
|
||||||
target_link_libraries(gltfio-jni dracodec meshoptimizer)
|
target_link_libraries(gltfio-jni dracodec meshoptimizer)
|
||||||
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
|
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
|
||||||
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
|
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.59.3
|
VERSION_NAME=1.58.0
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
@@ -200,9 +200,8 @@ WEBGPU_ANDROID_GRADLE_OPTION=""
|
|||||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
||||||
|
|
||||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
||||||
MATDBG_GRADLE_OPTION=""
|
|
||||||
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
|
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
|
||||||
FGVIEWER_GRADLE_OPTION=""
|
MATDBG_GRADLE_OPTION=""
|
||||||
|
|
||||||
MATOPT_OPTION=""
|
MATOPT_OPTION=""
|
||||||
MATOPT_GRADLE_OPTION=""
|
MATOPT_GRADLE_OPTION=""
|
||||||
@@ -534,7 +533,6 @@ function build_android {
|
|||||||
${VULKAN_ANDROID_GRADLE_OPTION} \
|
${VULKAN_ANDROID_GRADLE_OPTION} \
|
||||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||||
${MATDBG_GRADLE_OPTION} \
|
${MATDBG_GRADLE_OPTION} \
|
||||||
${FGVIEWER_GRADLE_OPTION} \
|
|
||||||
${MATOPT_GRADLE_OPTION} \
|
${MATOPT_GRADLE_OPTION} \
|
||||||
:filament-android:assembleDebug \
|
:filament-android:assembleDebug \
|
||||||
:gltfio-android:assembleDebug \
|
:gltfio-android:assembleDebug \
|
||||||
@@ -586,7 +584,6 @@ function build_android {
|
|||||||
${VULKAN_ANDROID_GRADLE_OPTION} \
|
${VULKAN_ANDROID_GRADLE_OPTION} \
|
||||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||||
${MATDBG_GRADLE_OPTION} \
|
${MATDBG_GRADLE_OPTION} \
|
||||||
${FGVIEWER_GRADLE_OPTION} \
|
|
||||||
${MATOPT_GRADLE_OPTION} \
|
${MATOPT_GRADLE_OPTION} \
|
||||||
:filament-android:assembleRelease \
|
:filament-android:assembleRelease \
|
||||||
:gltfio-android:assembleRelease \
|
:gltfio-android:assembleRelease \
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
|||||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||||
|
|
||||||
# For dawn
|
|
||||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
|
||||||
|
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||||
fi
|
fi
|
||||||
|
|||||||
+16
-24
@@ -13,7 +13,7 @@ This document is part of the [Filament project](https://github.com/google/filame
|
|||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
- [Romain Guy](https://github.com/romainguy), [@romainguy](https://twitter.com/romainguy)
|
- [Romain Guy](https://github.com/romainguy), [@romainguy](https://twitter.com/romainguy)
|
||||||
- [Mathias Agopian](https://github.com/pixelflinger), [@pixelflinger](https://bsky.app/profile/pixelflinger.bsky.social)
|
- [Mathias Agopian](https://github.com/pixelflinger), [@darthmoosious](https://twitter.com/darthmoosious)
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
@@ -78,27 +78,26 @@ in table [standardProperties].
|
|||||||
Property | Definition
|
Property | Definition
|
||||||
-----------------------:|:---------------------
|
-----------------------:|:---------------------
|
||||||
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
|
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
|
||||||
**roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
|
|
||||||
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
|
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
|
||||||
|
**roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
|
||||||
**reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
|
**reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
|
||||||
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
|
|
||||||
**clearCoat** | Strength of the clear coat layer
|
|
||||||
**clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer
|
|
||||||
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
|
|
||||||
**anisotropy** | Amount of anisotropy in either the tangent or bitangent direction
|
|
||||||
**anisotropyDirection** | Local surface direction in tangent space
|
|
||||||
**thickness** | Thickness of the solid volume of refractive objects
|
|
||||||
**sheenColor** | Strength of the sheen layer
|
**sheenColor** | Strength of the sheen layer
|
||||||
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
|
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
|
||||||
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
|
**clearCoat** | Strength of the clear coat layer
|
||||||
|
**clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer
|
||||||
|
**anisotropy** | Amount of anisotropy in either the tangent or bitangent direction
|
||||||
|
**anisotropyDirection** | Local surface direction in tangent space
|
||||||
|
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
|
||||||
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
|
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
|
||||||
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
|
|
||||||
**absorption** | Absorption factor for refractive objects
|
|
||||||
**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
|
|
||||||
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
|
**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
|
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
|
||||||
|
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
|
||||||
|
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
|
||||||
|
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
|
||||||
|
**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
|
||||||
|
**absorption** | Absorption factor for refractive objects
|
||||||
|
**microThickness** | Thickness of the thin layer of refractive objects
|
||||||
|
**thickness** | Thickness of the solid volume of refractive objects
|
||||||
[Table [standardProperties]: Properties of the standard model]
|
[Table [standardProperties]: Properties of the standard model]
|
||||||
|
|
||||||
The type and range of each property is described in table [standardPropertiesTypes].
|
The type and range of each property is described in table [standardPropertiesTypes].
|
||||||
@@ -1273,9 +1272,6 @@ Description
|
|||||||
when selecting any shading model that is not `unlit`. See the shader sections of this document
|
when selecting any shading model that is not `unlit`. See the shader sections of this document
|
||||||
for more information on how to access these attributes from the shaders.
|
for more information on how to access these attributes from the shaders.
|
||||||
|
|
||||||
!!! Note: Interaction with custom variables
|
|
||||||
When the `color` attribute is specified, only four custom variables are available instead of five.
|
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||||
material {
|
material {
|
||||||
parameters : [
|
parameters : [
|
||||||
@@ -1306,7 +1302,7 @@ Type
|
|||||||
: array of `string`
|
: array of `string`
|
||||||
|
|
||||||
Value
|
Value
|
||||||
: Up to 5 strings, each must be a valid GLSL identifier.
|
: Up to 4 strings, each must be a valid GLSL identifier.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
||||||
@@ -1322,10 +1318,6 @@ Description
|
|||||||
particular if `default` is specified the default precision is used is the fragment shader
|
particular if `default` is specified the default precision is used is the fragment shader
|
||||||
(`mediump`) and in the vertex shader (`highp`).
|
(`mediump`) and in the vertex shader (`highp`).
|
||||||
|
|
||||||
!!! Warning: Interaction with required attributes
|
|
||||||
If the `color` attribute is specified in the `required` list, then only four variables can be used
|
|
||||||
instead of five.
|
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||||
material {
|
material {
|
||||||
name : Skybox,
|
name : Skybox,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -108,12 +108,8 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3)
|
|||||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
|
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
|
||||||
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
|
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformOSMesa.cpp)
|
|
||||||
else()
|
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
||||||
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
|
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
|
||||||
endif()
|
|
||||||
elseif (WEBGL)
|
elseif (WEBGL)
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
||||||
elseif (LINUX)
|
elseif (LINUX)
|
||||||
@@ -177,6 +173,27 @@ endif()
|
|||||||
if (FILAMENT_SUPPORTS_VULKAN)
|
if (FILAMENT_SUPPORTS_VULKAN)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
include/backend/platforms/VulkanPlatform.h
|
include/backend/platforms/VulkanPlatform.h
|
||||||
|
src/vulkan/caching/VulkanDescriptorSetManager.cpp
|
||||||
|
src/vulkan/caching/VulkanDescriptorSetManager.h
|
||||||
|
src/vulkan/caching/VulkanPipelineLayoutCache.cpp
|
||||||
|
src/vulkan/caching/VulkanPipelineLayoutCache.h
|
||||||
|
src/vulkan/memory/ResourceManager.cpp
|
||||||
|
src/vulkan/memory/ResourceManager.h
|
||||||
|
src/vulkan/memory/ResourcePointer.h
|
||||||
|
src/vulkan/memory/Resource.cpp
|
||||||
|
src/vulkan/memory/Resource.h
|
||||||
|
src/vulkan/platform/VulkanPlatform.cpp
|
||||||
|
src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp
|
||||||
|
src/vulkan/platform/VulkanPlatformSwapChainImpl.h
|
||||||
|
src/vulkan/utils/Conversion.cpp
|
||||||
|
src/vulkan/utils/Conversion.h
|
||||||
|
src/vulkan/utils/Definitions.h
|
||||||
|
src/vulkan/utils/Helper.h
|
||||||
|
src/vulkan/utils/Image.h
|
||||||
|
src/vulkan/utils/Image.cpp
|
||||||
|
src/vulkan/utils/Spirv.h
|
||||||
|
src/vulkan/utils/Spirv.cpp
|
||||||
|
src/vulkan/utils/StaticVector.h
|
||||||
src/vulkan/VulkanAsyncHandles.h
|
src/vulkan/VulkanAsyncHandles.h
|
||||||
src/vulkan/VulkanBlitter.cpp
|
src/vulkan/VulkanBlitter.cpp
|
||||||
src/vulkan/VulkanBlitter.h
|
src/vulkan/VulkanBlitter.h
|
||||||
@@ -187,10 +204,6 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
src/vulkan/VulkanConstants.h
|
src/vulkan/VulkanConstants.h
|
||||||
src/vulkan/VulkanContext.cpp
|
src/vulkan/VulkanContext.cpp
|
||||||
src/vulkan/VulkanContext.h
|
src/vulkan/VulkanContext.h
|
||||||
src/vulkan/VulkanDescriptorSetCache.cpp
|
|
||||||
src/vulkan/VulkanDescriptorSetCache.h
|
|
||||||
src/vulkan/VulkanDescriptorSetLayoutCache.cpp
|
|
||||||
src/vulkan/VulkanDescriptorSetLayoutCache.h
|
|
||||||
src/vulkan/VulkanDriver.cpp
|
src/vulkan/VulkanDriver.cpp
|
||||||
src/vulkan/VulkanDriver.h
|
src/vulkan/VulkanDriver.h
|
||||||
src/vulkan/VulkanDriverFactory.h
|
src/vulkan/VulkanDriverFactory.h
|
||||||
@@ -198,43 +211,22 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
src/vulkan/VulkanFboCache.h
|
src/vulkan/VulkanFboCache.h
|
||||||
src/vulkan/VulkanHandles.cpp
|
src/vulkan/VulkanHandles.cpp
|
||||||
src/vulkan/VulkanHandles.h
|
src/vulkan/VulkanHandles.h
|
||||||
src/vulkan/VulkanMemory.cpp
|
|
||||||
src/vulkan/VulkanMemory.h
|
src/vulkan/VulkanMemory.h
|
||||||
|
src/vulkan/VulkanMemory.cpp
|
||||||
src/vulkan/VulkanPipelineCache.cpp
|
src/vulkan/VulkanPipelineCache.cpp
|
||||||
src/vulkan/VulkanPipelineCache.h
|
src/vulkan/VulkanPipelineCache.h
|
||||||
src/vulkan/VulkanPipelineLayoutCache.cpp
|
|
||||||
src/vulkan/VulkanPipelineLayoutCache.h
|
|
||||||
src/vulkan/VulkanQueryManager.cpp
|
src/vulkan/VulkanQueryManager.cpp
|
||||||
src/vulkan/VulkanQueryManager.h
|
src/vulkan/VulkanQueryManager.h
|
||||||
src/vulkan/VulkanReadPixels.cpp
|
|
||||||
src/vulkan/VulkanReadPixels.h
|
|
||||||
src/vulkan/VulkanSamplerCache.cpp
|
src/vulkan/VulkanSamplerCache.cpp
|
||||||
src/vulkan/VulkanSamplerCache.h
|
src/vulkan/VulkanSamplerCache.h
|
||||||
src/vulkan/VulkanStagePool.cpp
|
src/vulkan/VulkanStagePool.cpp
|
||||||
src/vulkan/VulkanStagePool.h
|
src/vulkan/VulkanStagePool.h
|
||||||
src/vulkan/VulkanSwapChain.cpp
|
src/vulkan/VulkanSwapChain.cpp
|
||||||
src/vulkan/VulkanSwapChain.h
|
src/vulkan/VulkanSwapChain.h
|
||||||
|
src/vulkan/VulkanReadPixels.cpp
|
||||||
|
src/vulkan/VulkanReadPixels.h
|
||||||
src/vulkan/VulkanTexture.cpp
|
src/vulkan/VulkanTexture.cpp
|
||||||
src/vulkan/VulkanTexture.h
|
src/vulkan/VulkanTexture.h
|
||||||
src/vulkan/VulkanYcbcrConversionCache.cpp
|
|
||||||
src/vulkan/VulkanYcbcrConversionCache.h
|
|
||||||
src/vulkan/memory/Resource.cpp
|
|
||||||
src/vulkan/memory/Resource.h
|
|
||||||
src/vulkan/memory/ResourceManager.cpp
|
|
||||||
src/vulkan/memory/ResourceManager.h
|
|
||||||
src/vulkan/memory/ResourcePointer.h
|
|
||||||
src/vulkan/platform/VulkanPlatform.cpp
|
|
||||||
src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp
|
|
||||||
src/vulkan/platform/VulkanPlatformSwapChainImpl.h
|
|
||||||
src/vulkan/utils/Conversion.cpp
|
|
||||||
src/vulkan/utils/Conversion.h
|
|
||||||
src/vulkan/utils/Definitions.h
|
|
||||||
src/vulkan/utils/Helper.h
|
|
||||||
src/vulkan/utils/Image.cpp
|
|
||||||
src/vulkan/utils/Image.h
|
|
||||||
src/vulkan/utils/Spirv.cpp
|
|
||||||
src/vulkan/utils/Spirv.h
|
|
||||||
src/vulkan/utils/StaticVector.h
|
|
||||||
)
|
)
|
||||||
if (LINUX OR WIN32)
|
if (LINUX OR WIN32)
|
||||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp)
|
list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp)
|
||||||
@@ -250,36 +242,11 @@ endif()
|
|||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
include/backend/platforms/WebGPUPlatform.h
|
|
||||||
src/webgpu/platform/WebGPUPlatform.cpp
|
|
||||||
src/webgpu/WebGPUConstants.h
|
|
||||||
src/webgpu/WebGPUDriver.cpp
|
src/webgpu/WebGPUDriver.cpp
|
||||||
src/webgpu/WebGPUDriver.h
|
src/webgpu/WebGPUDriver.h
|
||||||
src/webgpu/WebGPUHandles.cpp
|
src/webgpu/WebGPUPlatform.cpp
|
||||||
src/webgpu/WebGPUHandles.h
|
src/webgpu/WebGPUPlatform.h
|
||||||
src/webgpu/WebGPUSwapChain.cpp
|
|
||||||
src/webgpu/WebGPUSwapChain.h
|
|
||||||
src/webgpu/WGPUProgram.cpp
|
|
||||||
)
|
)
|
||||||
if (WIN32)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp)
|
|
||||||
elseif (LINUX)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformLinux.cpp)
|
|
||||||
elseif (APPLE OR IOS)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformApple.mm)
|
|
||||||
elseif (ANDROID)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformAndroid.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (TNT_DEV)
|
|
||||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT ON)
|
|
||||||
else()
|
|
||||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING
|
|
||||||
"Enable immediate_error_handling for the WebGPU backend Dawn implementation"
|
|
||||||
${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
@@ -309,11 +276,6 @@ target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
|||||||
# add this subproject to the Filament folder
|
# add this subproject to the Filament folder
|
||||||
set_target_properties(${TARGET} PROPERTIES FOLDER Filament)
|
set_target_properties(${TARGET} PROPERTIES FOLDER Filament)
|
||||||
|
|
||||||
# we need to export the headers properly for backend.lib on windows
|
|
||||||
if (WIN32 AND FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
target_compile_definitions(${TARGET} PRIVATE "WGPU_IMPLEMENTATION")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Expose a header-only target to minimize dependencies.
|
# Expose a header-only target to minimize dependencies.
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -434,12 +396,9 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS
|
|||||||
-Wl,--exclude-libs,bluegl
|
-Wl,--exclude-libs,bluegl
|
||||||
)
|
)
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
if (LINUX AND FILAMENT_SUPPORTS_OSMESA)
|
||||||
if (LINUX)
|
set(OSMESA_COMPILE_FLAGS
|
||||||
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL)
|
-I${FILAMENT_OSMESA_PATH}/include/GL)
|
||||||
elseif (APPLE)
|
|
||||||
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
@@ -474,10 +433,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_METAL_PROFILING}>:FILAMENT_METAL_PROFILING>)
|
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_METAL_PROFILING}>:FILAMENT_METAL_PROFILING>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(${TARGET} PRIVATE
|
target_link_libraries(${TARGET} PRIVATE
|
||||||
${OSMESA_LINKER_FLAGS}
|
${OSMESA_LINKER_FLAGS}
|
||||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||||
@@ -506,12 +461,7 @@ if (APPLE OR LINUX)
|
|||||||
test/ShaderGenerator.cpp
|
test/ShaderGenerator.cpp
|
||||||
test/TrianglePrimitive.cpp
|
test/TrianglePrimitive.cpp
|
||||||
test/Arguments.cpp
|
test/Arguments.cpp
|
||||||
test/ImageExpectations.cpp
|
|
||||||
test/Lifetimes.cpp
|
test/Lifetimes.cpp
|
||||||
test/PlatformRunner.cpp
|
|
||||||
test/Shader.cpp
|
|
||||||
test/SharedShaders.cpp
|
|
||||||
test/Skip.cpp
|
|
||||||
test/test_FeedbackLoops.cpp
|
test/test_FeedbackLoops.cpp
|
||||||
test/test_Blit.cpp
|
test/test_Blit.cpp
|
||||||
test/test_MissingRequiredAttributes.cpp
|
test/test_MissingRequiredAttributes.cpp
|
||||||
@@ -527,7 +477,6 @@ if (APPLE OR LINUX)
|
|||||||
test/test_Handles.cpp
|
test/test_Handles.cpp
|
||||||
)
|
)
|
||||||
set(BACKEND_TEST_LIBS
|
set(BACKEND_TEST_LIBS
|
||||||
absl::str_format
|
|
||||||
backend
|
backend
|
||||||
getopt
|
getopt
|
||||||
gtest
|
gtest
|
||||||
@@ -535,9 +484,6 @@ if (APPLE OR LINUX)
|
|||||||
filamat
|
filamat
|
||||||
SPIRV
|
SPIRV
|
||||||
spirv-cross-glsl)
|
spirv-cross-glsl)
|
||||||
# Create input/output directories for test result images.
|
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/images/actual_images)
|
|
||||||
file(COPY test/expected_images DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/images)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO: Disabling IOS test due to breakage wrt glslang update
|
# TODO: Disabling IOS test due to breakage wrt glslang update
|
||||||
@@ -546,7 +492,7 @@ if (APPLE AND NOT IOS)
|
|||||||
list(APPEND BACKEND_TEST_SRC
|
list(APPEND BACKEND_TEST_SRC
|
||||||
test/test_RenderExternalImage.cpp)
|
test/test_RenderExternalImage.cpp)
|
||||||
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||||
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
target_link_libraries(backend_test PRIVATE ${BACKEND_TEST_LIBS})
|
||||||
|
|
||||||
set(BACKEND_TEST_DEPS
|
set(BACKEND_TEST_DEPS
|
||||||
OSDependent
|
OSDependent
|
||||||
|
|||||||
@@ -55,9 +55,4 @@ public:
|
|||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
|
||||||
utils::io::ostream& operator<<(utils::io::ostream& out,
|
|
||||||
const filament::backend::BufferObjectStreamDescriptor& b);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TNT_FILAMENT_BACKEND_BUFFEROBJECTSTREAMDESCRIPTOR_H
|
#endif // TNT_FILAMENT_BACKEND_BUFFEROBJECTSTREAMDESCRIPTOR_H
|
||||||
|
|||||||
@@ -126,10 +126,6 @@ static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
|||||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||||
|
|
||||||
static constexpr uint8_t EXTERNAL_SAMPLER_DATA_INDEX_UNUSED =
|
|
||||||
uint8_t(-1);// Case where the descriptor set binding isnt using any external sampler state
|
|
||||||
// and therefore doesn't have a valid entry.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the backend's feature levels.
|
* Defines the backend's feature levels.
|
||||||
*/
|
*/
|
||||||
@@ -256,21 +252,21 @@ struct DescriptorSetLayoutBinding {
|
|||||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
|
|
||||||
// TODO: uncomment when needed. Note that this class is used as hash key. We need to ensure
|
friend inline bool operator==(
|
||||||
// no uninitialized padding bytes.
|
DescriptorSetLayoutBinding const& lhs,
|
||||||
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
|
||||||
|
|
||||||
friend inline bool operator==(DescriptorSetLayoutBinding const& lhs,
|
|
||||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||||
return lhs.type == rhs.type &&
|
return lhs.type == rhs.type &&
|
||||||
lhs.flags == rhs.flags &&
|
lhs.flags == rhs.flags &&
|
||||||
lhs.count == rhs.count &&
|
lhs.count == rhs.count &&
|
||||||
lhs.stageFlags == rhs.stageFlags;
|
lhs.stageFlags == rhs.stageFlags;
|
||||||
// lhs.stageFlags == rhs.stageFlags &&
|
|
||||||
// lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DescriptorSetLayout {
|
||||||
|
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitmask for selecting render buffers
|
* Bitmask for selecting render buffers
|
||||||
*/
|
*/
|
||||||
@@ -972,26 +968,6 @@ enum class SamplerCompareFunc : uint8_t {
|
|||||||
N //!< Never. The depth / stencil test always fails.
|
N //!< Never. The depth / stencil test always fails.
|
||||||
};
|
};
|
||||||
|
|
||||||
//! this API is copied from (and only applies to) the Vulkan spec.
|
|
||||||
//! These specify YUV to RGB conversions.
|
|
||||||
enum class SamplerYcbcrModelConversion : uint8_t {
|
|
||||||
RGB_IDENTITY = 0,
|
|
||||||
YCBCR_IDENTITY = 1,
|
|
||||||
YCBCR_709 = 2,
|
|
||||||
YCBCR_601 = 3,
|
|
||||||
YCBCR_2020 = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerYcbcrRange : uint8_t {
|
|
||||||
ITU_FULL = 0,
|
|
||||||
ITU_NARROW = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ChromaLocation : uint8_t {
|
|
||||||
COSITED_EVEN = 0,
|
|
||||||
MIDPOINT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Sampler parameters
|
//! Sampler parameters
|
||||||
struct SamplerParams { // NOLINT
|
struct SamplerParams { // NOLINT
|
||||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||||
@@ -1048,7 +1024,6 @@ private:
|
|||||||
return SamplerParams::LessThan{}(lhs, rhs);
|
return SamplerParams::LessThan{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(SamplerParams) == 4);
|
static_assert(sizeof(SamplerParams) == 4);
|
||||||
|
|
||||||
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
||||||
@@ -1056,95 +1031,6 @@ static_assert(sizeof(SamplerParams) == 4);
|
|||||||
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
||||||
"SamplerParams must be no more than 64 bits");
|
"SamplerParams must be no more than 64 bits");
|
||||||
|
|
||||||
//! Sampler parameters
|
|
||||||
struct SamplerYcbcrConversion {// NOLINT
|
|
||||||
SamplerYcbcrModelConversion ycbcrModel : 4;
|
|
||||||
TextureSwizzle r : 4;
|
|
||||||
TextureSwizzle g : 4;
|
|
||||||
TextureSwizzle b : 4;
|
|
||||||
TextureSwizzle a : 4;
|
|
||||||
SamplerYcbcrRange ycbcrRange : 1;
|
|
||||||
ChromaLocation xChromaOffset : 1;
|
|
||||||
ChromaLocation yChromaOffset : 1;
|
|
||||||
SamplerMagFilter chromaFilter : 1;
|
|
||||||
uint8_t padding;
|
|
||||||
|
|
||||||
struct Hasher {
|
|
||||||
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
|
|
||||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
|
||||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EqualTo {
|
|
||||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
|
||||||
assert_invariant(lhs.padding == 0);
|
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
|
||||||
return *pLhs == *pRhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LessThan {
|
|
||||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
|
||||||
assert_invariant(lhs.padding == 0);
|
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
|
||||||
return *pLhs < *pRhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(SamplerYcbcrConversion) == 4);
|
|
||||||
|
|
||||||
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
|
|
||||||
"SamplerYcbcrConversion must be no more than 64 bits");
|
|
||||||
|
|
||||||
struct ExternalSamplerDatum {
|
|
||||||
ExternalSamplerDatum(SamplerYcbcrConversion ycbcr, SamplerParams spm, uint32_t extFmt)
|
|
||||||
: YcbcrConversion(ycbcr),
|
|
||||||
samplerParams(spm),
|
|
||||||
externalFormat(extFmt) {}
|
|
||||||
bool operator==(ExternalSamplerDatum const& rhs) const {
|
|
||||||
return (YcbcrConversion == rhs.YcbcrConversion && samplerParams == rhs.samplerParams &&
|
|
||||||
externalFormat == rhs.externalFormat);
|
|
||||||
}
|
|
||||||
struct EqualTo {
|
|
||||||
bool operator()(const ExternalSamplerDatum& lhs,
|
|
||||||
const ExternalSamplerDatum& rhs) const noexcept {
|
|
||||||
return (lhs.YcbcrConversion == rhs.YcbcrConversion &&
|
|
||||||
lhs.samplerParams == rhs.samplerParams &&
|
|
||||||
lhs.externalFormat == rhs.externalFormat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SamplerYcbcrConversion YcbcrConversion;
|
|
||||||
SamplerParams samplerParams;
|
|
||||||
uint32_t externalFormat;
|
|
||||||
};
|
|
||||||
// No implicit padding allowed due to it being a hash key.
|
|
||||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
|
||||||
|
|
||||||
struct DescriptorSetLayout {
|
|
||||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
|
||||||
|
|
||||||
// TODO: uncomment when needed
|
|
||||||
// utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! blending equation function
|
//! blending equation function
|
||||||
enum class BlendEquation : uint8_t {
|
enum class BlendEquation : uint8_t {
|
||||||
ADD, //!< the fragment is added to the color buffer
|
ADD, //!< the fragment is added to the color buffer
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
PlatformCocoaGL();
|
PlatformCocoaGL();
|
||||||
~PlatformCocoaGL() noexcept override;
|
~PlatformCocoaGL() noexcept override;
|
||||||
|
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
PlatformCocoaTouchGL();
|
PlatformCocoaTouchGL();
|
||||||
~PlatformCocoaTouchGL() noexcept override;
|
~PlatformCocoaTouchGL() noexcept override;
|
||||||
|
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Platform Interface
|
// Platform Interface
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Creates an ExternalImage from a EGLImageKHR
|
* Creates an ExternalImage from a EGLImageKHR
|
||||||
*/
|
*/
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(EGLImageKHR eglImage) noexcept;
|
ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <backend/platforms/PlatformEGL.h>
|
#include <backend/platforms/PlatformEGL.h>
|
||||||
|
|
||||||
#include <utils/android/PerformanceHintManager.h>
|
#include <utils/android/PerformanceHintManager.h>
|
||||||
#include <utils/compiler.h>
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@@ -44,21 +43,8 @@ public:
|
|||||||
PlatformEGLAndroid() noexcept;
|
PlatformEGLAndroid() noexcept;
|
||||||
~PlatformEGLAndroid() noexcept override;
|
~PlatformEGLAndroid() noexcept override;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an ExternalImage from a EGLImageKHR
|
|
||||||
*/
|
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept;
|
|
||||||
|
|
||||||
struct UTILS_PUBLIC ExternalImageDescAndroid {
|
|
||||||
uint32_t width; // Texture width
|
|
||||||
uint32_t height; // Texture height
|
|
||||||
TextureFormat format;// Texture format
|
|
||||||
TextureUsage usage; // Texture usage flags
|
|
||||||
};
|
|
||||||
|
|
||||||
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(ExternalImageHandle externalImage) noexcept;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Platform Interface
|
// Platform Interface
|
||||||
|
|
||||||
@@ -71,6 +57,11 @@ protected:
|
|||||||
Driver* createDriver(void* sharedContext,
|
Driver* createDriver(void* sharedContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ExternalImage from a EGLImageKHR
|
||||||
|
*/
|
||||||
|
ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// OpenGLPlatform Interface
|
// OpenGLPlatform Interface
|
||||||
|
|
||||||
@@ -104,26 +95,15 @@ protected:
|
|||||||
*/
|
*/
|
||||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
||||||
|
|
||||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override;
|
||||||
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
|
|
||||||
|
|
||||||
struct ExternalImageEGLAndroid : public ExternalImageEGL {
|
struct ExternalImageEGLAndroid : public ExternalImageEGL {
|
||||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||||
uint32_t width; // Texture width
|
|
||||||
uint32_t height; // Texture height
|
|
||||||
TextureFormat format;// Texture format
|
|
||||||
TextureUsage usage; // Texture usage flags
|
|
||||||
bool sRGB = false;
|
bool sRGB = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ExternalImageEGLAndroid() override;
|
~ExternalImageEGLAndroid() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool setExternalImage(ExternalImageHandleRef externalImage,
|
|
||||||
ExternalTexture* texture) noexcept override;
|
|
||||||
bool setImage(ExternalImageEGLAndroid const* eglExternalImage,
|
|
||||||
ExternalTexture* texture) noexcept;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool makeCurrent(ContextType type,
|
bool makeCurrent(ContextType type,
|
||||||
SwapChain* drawSwapChain,
|
SwapChain* drawSwapChain,
|
||||||
|
|||||||
@@ -21,12 +21,7 @@
|
|||||||
|
|
||||||
#include "bluegl/BlueGL.h"
|
#include "bluegl/BlueGL.h"
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <osmesa.h>
|
#include <osmesa.h>
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#undef GLAPI
|
|
||||||
#include <GL/osmesa.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <backend/platforms/OpenGLPlatform.h>
|
#include <backend/platforms/OpenGLPlatform.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -104,6 +103,10 @@ public:
|
|||||||
|
|
||||||
// Semaphore to be signaled once the image is available.
|
// Semaphore to be signaled once the image is available.
|
||||||
VkSemaphore imageReadySemaphore = VK_NULL_HANDLE;
|
VkSemaphore imageReadySemaphore = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// A function called right before vkQueueSubmit. After this call, the image must be
|
||||||
|
// available. This pointer can be null if imageReadySemaphore is not VK_NULL_HANDLE.
|
||||||
|
std::function<void(SwapChainPtr handle)> explicitImageReadyWait = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
VulkanPlatform();
|
VulkanPlatform();
|
||||||
@@ -314,11 +317,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32_t layers;
|
uint32_t layers;
|
||||||
|
|
||||||
/**
|
|
||||||
* The numbers of samples per texel
|
|
||||||
*/
|
|
||||||
VkSampleCountFlagBits samples;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The format of the external image
|
* The format of the external image
|
||||||
*/
|
*/
|
||||||
@@ -353,43 +351,20 @@ public:
|
|||||||
|
|
||||||
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||||
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
const ExternalImageMetadata& metadata);
|
||||||
VkImageUsageFlags usage);
|
|
||||||
|
|
||||||
virtual VkSampler createExternalSampler(SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler, uint32_t internalFormat);
|
|
||||||
|
|
||||||
virtual VkImageView createExternalImageView(SamplerYcbcrConversion chroma,
|
|
||||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
|
||||||
VkImageViewType viewType, VkComponentMapping swizzle);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ExtensionSet getSwapchainInstanceExtensions() const;
|
|
||||||
|
|
||||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
|
||||||
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
|
||||||
uint64_t flags) const noexcept;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Platform dependent helper methods
|
static ExtensionSet getSwapchainInstanceExtensions();
|
||||||
static ExtensionSet getSwapchainInstanceExtensionsImpl();
|
|
||||||
|
|
||||||
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||||
VkDevice device);
|
VkDevice device);
|
||||||
|
|
||||||
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
||||||
VkDevice device, const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
VkDevice device, const ExternalImageMetadata& metadata);
|
||||||
VkImageUsageFlags usage);
|
|
||||||
static VkSampler createExternalSamplerImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, SamplerParams sampler,
|
|
||||||
uint32_t internalFormat);
|
|
||||||
static VkImageView createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType,
|
|
||||||
VkComponentMapping swizzle);
|
|
||||||
|
|
||||||
// Platform dependent helper methods
|
// Platform dependent helper methods
|
||||||
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
|
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||||
|
static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||||
uint64_t flags) noexcept;
|
uint64_t flags) noexcept;
|
||||||
|
|
||||||
friend struct VulkanPlatformPrivate;
|
friend struct VulkanPlatformPrivate;
|
||||||
|
|||||||
@@ -17,55 +17,27 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
|
||||||
|
|
||||||
#include <android/hardware_buffer.h>
|
#include <android/hardware_buffer.h>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend::fvkandroid {
|
||||||
|
|
||||||
class VulkanPlatformAndroid : public VulkanPlatform {
|
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
||||||
public:
|
|
||||||
Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
|
|
||||||
bool sRGB) noexcept;
|
|
||||||
|
|
||||||
struct UTILS_PUBLIC ExternalImageDescAndroid {
|
|
||||||
uint32_t width; // Texture width
|
|
||||||
uint32_t height; // Texture height
|
|
||||||
TextureFormat format;// Texture format
|
|
||||||
TextureUsage usage; // Texture usage flags
|
|
||||||
};
|
|
||||||
|
|
||||||
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
|
|
||||||
ExternalImageHandleRef externalImage) const noexcept;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
|
||||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||||
bool sRGB = false;
|
bool sRGB = false;
|
||||||
unsigned int width; // Texture width
|
unsigned int width; // Texture width
|
||||||
unsigned int height; // Texture height
|
unsigned int height; // Texture height
|
||||||
TextureFormat format;// Texture format
|
TextureFormat format; // Texture format
|
||||||
TextureUsage usage; // Texture usage flags
|
TextureUsage usage; // Texture usage flags
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ExternalImageVulkanAndroid() override;
|
~ExternalImageVulkanAndroid() override;
|
||||||
};
|
|
||||||
|
|
||||||
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
|
|
||||||
|
|
||||||
using ImageData = VulkanPlatform::ImageData;
|
|
||||||
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
|
||||||
VkImageUsageFlags usage);
|
|
||||||
|
|
||||||
virtual ExtensionSet getSwapchainInstanceExtensions() const;
|
|
||||||
|
|
||||||
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
|
|
||||||
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
|
||||||
uint64_t flags) const noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace filament::backend
|
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||||
|
bool sRGB) noexcept;
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
} // namespace filament::backend::fvkandroid
|
||||||
|
|
||||||
|
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Platform interface, handling the environment-specific concerns, e.g. OS, for creating a WebGPU
|
|
||||||
* driver (backend).
|
|
||||||
*/
|
|
||||||
class WebGPUPlatform final : public Platform {
|
|
||||||
public:
|
|
||||||
WebGPUPlatform();
|
|
||||||
~WebGPUPlatform() override = default;
|
|
||||||
|
|
||||||
[[nodiscard]] int getOSVersion() const noexcept final { return 0; }
|
|
||||||
|
|
||||||
[[nodiscard]] wgpu::Instance& getInstance() noexcept { return mInstance; }
|
|
||||||
|
|
||||||
// TODO consider that this functionality is not WebGPU-specific, and thus could be
|
|
||||||
// placed in a generic place and even reused across backends. Alternatively,
|
|
||||||
// a 3rd party library could be considered. However, this was a simple and
|
|
||||||
// quick change and works for now.
|
|
||||||
// gets the size (height and width) of the surface/window
|
|
||||||
[[nodiscard]] wgpu::Extent2D getSurfaceExtent(void* nativeWindow) const;
|
|
||||||
// either returns a valid surface or panics
|
|
||||||
[[nodiscard]] wgpu::Surface createSurface(void* nativeWindow, uint64_t flags);
|
|
||||||
// either returns a valid adapter or panics
|
|
||||||
[[nodiscard]] wgpu::Adapter requestAdapter(wgpu::Surface const& surface);
|
|
||||||
// either returns a valid device or panics
|
|
||||||
[[nodiscard]] wgpu::Device requestDevice(wgpu::Adapter const& adapter);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] Driver* createDriver(void* sharedContext,
|
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// we may consider having the driver own this in the future
|
|
||||||
wgpu::Instance mInstance;
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
@@ -362,8 +362,6 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
|
|||||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(size_t, getMaxTextureSize, backend::SamplerType, target)
|
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxArrayTextureLayers)
|
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
|
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
||||||
|
|||||||
@@ -43,8 +43,6 @@
|
|||||||
#define HandleAllocatorGL HandleAllocator<32, 96, 184> // ~4520 / pool / MiB
|
#define HandleAllocatorGL HandleAllocator<32, 96, 184> // ~4520 / pool / MiB
|
||||||
#define HandleAllocatorVK HandleAllocator<64, 160, 312> // ~1820 / pool / MiB
|
#define HandleAllocatorVK HandleAllocator<64, 160, 312> // ~1820 / pool / MiB
|
||||||
#define HandleAllocatorMTL HandleAllocator<32, 64, 552> // ~1660 / pool / MiB
|
#define HandleAllocatorMTL HandleAllocator<32, 64, 552> // ~1660 / pool / MiB
|
||||||
// TODO WebGPU examine right size of handles
|
|
||||||
#define HandleAllocatorWGPU HandleAllocator<64, 160, 552> // ~1820 / pool / MiB
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ void CommandStream::execute(void* buffer) {
|
|||||||
|
|
||||||
Profiler profiler;
|
Profiler profiler;
|
||||||
|
|
||||||
if constexpr (SYSTRACE_TAG) {
|
if (SYSTRACE_TAG) {
|
||||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||||
// we want to remove all this when tracing is completely disabled
|
// we want to remove all this when tracing is completely disabled
|
||||||
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
|
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
|
||||||
@@ -100,7 +100,7 @@ void CommandStream::execute(void* buffer) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if constexpr (SYSTRACE_TAG) {
|
if (SYSTRACE_TAG) {
|
||||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||||
// we want to remove all this when tracing is completely disabled
|
// we want to remove all this when tracing is completely disabled
|
||||||
profiler.stop();
|
profiler.stop();
|
||||||
|
|||||||
@@ -211,8 +211,4 @@ template class HandleAllocatorVK;
|
|||||||
template class HandleAllocatorMTL;
|
template class HandleAllocatorMTL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
template class HandleAllocatorWGPU;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -19,11 +19,6 @@
|
|||||||
#include <utils/Systrace.h>
|
#include <utils/Systrace.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
|
|
||||||
// We need to keep this up top for the linux (X11) name collisions.
|
|
||||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
#include "backend/platforms/WebGPUPlatform.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
@@ -35,12 +30,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
|
||||||
#include <backend/platforms/PlatformOSMesa.h>
|
|
||||||
#else
|
|
||||||
#include <backend/platforms/PlatformCocoaGL.h>
|
#include <backend/platforms/PlatformCocoaGL.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#if defined(FILAMENT_SUPPORTS_X11)
|
#if defined(FILAMENT_SUPPORTS_X11)
|
||||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
@@ -64,11 +55,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#include "backend/platforms/VulkanPlatformAndroid.h"
|
|
||||||
#else
|
|
||||||
#include "backend/platforms/VulkanPlatform.h"
|
#include "backend/platforms/VulkanPlatform.h"
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (FILAMENT_SUPPORTS_METAL)
|
#if defined (FILAMENT_SUPPORTS_METAL)
|
||||||
@@ -78,6 +65,9 @@ filament::backend::Platform* createDefaultMetalPlatform();
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "noop/PlatformNoop.h"
|
#include "noop/PlatformNoop.h"
|
||||||
|
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||||
|
#include "webgpu/WebGPUPlatform.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -114,11 +104,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
|||||||
}
|
}
|
||||||
if (*backend == Backend::VULKAN) {
|
if (*backend == Backend::VULKAN) {
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||||
#if defined(__ANDROID__)
|
|
||||||
return new VulkanPlatformAndroid();
|
|
||||||
#else
|
|
||||||
return new VulkanPlatform();
|
return new VulkanPlatform();
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
@@ -146,11 +132,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
|||||||
#elif defined(FILAMENT_IOS)
|
#elif defined(FILAMENT_IOS)
|
||||||
return new PlatformCocoaTouchGL();
|
return new PlatformCocoaTouchGL();
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
|
||||||
return new PlatformOSMesa();
|
|
||||||
#else
|
|
||||||
return new PlatformCocoaGL();
|
return new PlatformCocoaGL();
|
||||||
#endif
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#if defined(FILAMENT_SUPPORTS_X11)
|
#if defined(FILAMENT_SUPPORTS_X11)
|
||||||
return new PlatformGLX();
|
return new PlatformGLX();
|
||||||
|
|||||||
@@ -1177,24 +1177,6 @@ size_t MetalDriver::getMaxUniformBufferSize() {
|
|||||||
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MetalDriver::getMaxTextureSize(SamplerType type) {
|
|
||||||
if (type == SamplerType::SAMPLER_3D) {
|
|
||||||
return 2048;
|
|
||||||
}
|
|
||||||
if (mContext->highestSupportedGpuFamily.apple >= 3 ||
|
|
||||||
mContext->highestSupportedGpuFamily.mac >= 2) {
|
|
||||||
return 16384;
|
|
||||||
} else if (mContext->highestSupportedGpuFamily.apple >= 2) {
|
|
||||||
return 8192;
|
|
||||||
}
|
|
||||||
return 4096;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t MetalDriver::getMaxArrayTextureLayers() {
|
|
||||||
// TODO: return the actual size instead of hardcoding the minspec
|
|
||||||
return 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
FILAMENT_CHECK_PRECONDITION(data.buffer)
|
FILAMENT_CHECK_PRECONDITION(data.buffer)
|
||||||
|
|||||||
@@ -240,16 +240,6 @@ size_t NoopDriver::getMaxUniformBufferSize() {
|
|||||||
return 16384u;
|
return 16384u;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NoopDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
// NoopDriver is being actively used for other purposes. This needs to be resolved before we
|
|
||||||
// can change it to 2048. b/406832484
|
|
||||||
return 16384u;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t NoopDriver::getMaxArrayTextureLayers() {
|
|
||||||
return 256u;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
Driver* PlatformNoop::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
return NoopDriver::create();
|
return NoopDriver::create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,22 +94,18 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initExtensions(&ext, state.major, state.minor);
|
OpenGLContext::initExtensions(&ext, state.major, state.minor);
|
||||||
|
|
||||||
initProcs(&procs, ext, state.major, state.minor);
|
OpenGLContext::initProcs(&procs, ext, state.major, state.minor);
|
||||||
|
|
||||||
initBugs(&bugs, ext, state.major, state.minor,
|
OpenGLContext::initBugs(&bugs, ext, state.major, state.minor,
|
||||||
state.vendor, state.renderer, state.version, state.shader);
|
state.vendor, state.renderer, state.version, state.shader);
|
||||||
|
|
||||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
||||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gets.max_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gets.max_cubemap_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gets.max_3d_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gets.max_array_texture_layers);
|
|
||||||
|
|
||||||
mFeatureLevel = resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
mFeatureLevel = OpenGLContext::resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
||||||
|
|
||||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||||
mShaderModel = ShaderModel::MOBILE;
|
mShaderModel = ShaderModel::MOBILE;
|
||||||
@@ -181,14 +177,6 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
|||||||
<< gets.max_anisotropy << '\n'
|
<< gets.max_anisotropy << '\n'
|
||||||
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
||||||
<< gets.max_combined_texture_image_units << '\n'
|
<< gets.max_combined_texture_image_units << '\n'
|
||||||
<< "GL_MAX_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_texture_size << '\n'
|
|
||||||
<< "GL_MAX_CUBE_MAP_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_cubemap_texture_size << '\n'
|
|
||||||
<< "GL_MAX_3D_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_3d_texture_size << '\n'
|
|
||||||
<< "GL_MAX_ARRAY_TEXTURE_LAYERS = "
|
|
||||||
<< gets.max_array_texture_layers << '\n'
|
|
||||||
<< "GL_MAX_DRAW_BUFFERS = "
|
<< "GL_MAX_DRAW_BUFFERS = "
|
||||||
<< gets.max_draw_buffers << '\n'
|
<< gets.max_draw_buffers << '\n'
|
||||||
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
||||||
@@ -566,11 +554,7 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
|||||||
} else if (strstr(renderer, "AMD") ||
|
} else if (strstr(renderer, "AMD") ||
|
||||||
strstr(renderer, "ATI")) {
|
strstr(renderer, "ATI")) {
|
||||||
// AMD/ATI GPU
|
// AMD/ATI GPU
|
||||||
} else if (strstr(renderer, "Mozilla")) {
|
} else if (strstr(vendor, "Mesa")) {
|
||||||
bugs->disable_invalidate_framebuffer = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strstr(vendor, "Mesa")) {
|
|
||||||
// Seen on
|
// Seen on
|
||||||
// [Mesa],
|
// [Mesa],
|
||||||
// [llvmpipe (LLVM 17.0.6, 256 bits)],
|
// [llvmpipe (LLVM 17.0.6, 256 bits)],
|
||||||
@@ -578,6 +562,8 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
|||||||
// [4.50]
|
// [4.50]
|
||||||
// not known which version are affected
|
// not known which version are affected
|
||||||
bugs->rebind_buffer_after_deletion = true;
|
bugs->rebind_buffer_after_deletion = true;
|
||||||
|
} else if (strstr(renderer, "Mozilla")) {
|
||||||
|
bugs->disable_invalidate_framebuffer = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// When running under ANGLE, it's a different set of workaround that we need.
|
// When running under ANGLE, it's a different set of workaround that we need.
|
||||||
@@ -589,19 +575,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(vendor, "Mozilla")) {
|
|
||||||
// Seen on
|
|
||||||
// [Mozilla],
|
|
||||||
// [GeForce GTX 980, or similar]
|
|
||||||
// or [ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar]
|
|
||||||
// or anything else,
|
|
||||||
// [OpenGL ES 3.0 (WebGL 2.0)],
|
|
||||||
// [OpenGL ES GLSL ES 3.00 (WebGL GLSL ES 3.00)]
|
|
||||||
// For Mozilla, the issue appears to be observed regardless of whether the renderer is
|
|
||||||
// ANGLE or not. (b/376125497)
|
|
||||||
bugs->rebind_buffer_after_deletion = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||||
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
||||||
if (UTILS_UNLIKELY(major == 2)) {
|
if (UTILS_UNLIKELY(major == 2)) {
|
||||||
|
|||||||
@@ -203,10 +203,6 @@ public:
|
|||||||
GLint max_renderbuffer_size;
|
GLint max_renderbuffer_size;
|
||||||
GLint max_samples;
|
GLint max_samples;
|
||||||
GLint max_texture_image_units;
|
GLint max_texture_image_units;
|
||||||
GLint max_texture_size;
|
|
||||||
GLint max_cubemap_texture_size;
|
|
||||||
GLint max_3d_texture_size;
|
|
||||||
GLint max_array_texture_layers;
|
|
||||||
GLint max_transform_feedback_separate_attribs;
|
GLint max_transform_feedback_separate_attribs;
|
||||||
GLint max_uniform_block_size;
|
GLint max_uniform_block_size;
|
||||||
GLint max_uniform_buffer_bindings;
|
GLint max_uniform_buffer_bindings;
|
||||||
@@ -320,8 +316,8 @@ public:
|
|||||||
// a glFinish. So we must delay the destruction until we know the GPU is finished.
|
// a glFinish. So we must delay the destruction until we know the GPU is finished.
|
||||||
bool delay_fbo_destruction;
|
bool delay_fbo_destruction;
|
||||||
|
|
||||||
// Mesa and Mozilla(web) sometimes clear the generic buffer binding when *another* buffer
|
// Mesa sometimes clears the generic buffer binding when *another* buffer is destroyed,
|
||||||
// is destroyed, if that other buffer is bound on an *indexed* buffer binding.
|
// if that other buffer is bound on an *indexed* buffer binding.
|
||||||
bool rebind_buffer_after_deletion;
|
bool rebind_buffer_after_deletion;
|
||||||
|
|
||||||
// Force feature level 0. Typically used for low end ES3 devices with significant driver
|
// Force feature level 0. Typically used for low end ES3 devices with significant driver
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ using namespace utils;
|
|||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
Driver* OpenGLDriverFactory::create(
|
Driver* OpenGLDriverFactory::create(
|
||||||
OpenGLPlatform* platform,
|
OpenGLPlatform* const platform,
|
||||||
void* sharedGLContext,
|
void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
return OpenGLDriver::create(platform, sharedGLContext, driverConfig);
|
return OpenGLDriver::create(platform, sharedGLContext, driverConfig);
|
||||||
}
|
}
|
||||||
@@ -159,10 +159,10 @@ using namespace GLUtils;
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
|
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
||||||
void* /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
assert_invariant(platform);
|
assert_invariant(platform);
|
||||||
OpenGLPlatform* ec = platform;
|
OpenGLPlatform* const ec = platform;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// this is useful for development, but too verbose even for debug builds
|
// this is useful for development, but too verbose even for debug builds
|
||||||
@@ -230,7 +230,7 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
|
|||||||
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||||
Platform::DriverConfig validConfig{ driverConfig };
|
Platform::DriverConfig validConfig{ driverConfig };
|
||||||
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
||||||
OpenGLDriver* driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2460,26 +2460,6 @@ size_t OpenGLDriver::getMaxUniformBufferSize() {
|
|||||||
return mContext.gets.max_uniform_block_size;
|
return mContext.gets.max_uniform_block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OpenGLDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
switch (target) {
|
|
||||||
case SamplerType::SAMPLER_2D:
|
|
||||||
case SamplerType::SAMPLER_2D_ARRAY:
|
|
||||||
case SamplerType::SAMPLER_EXTERNAL:
|
|
||||||
return mContext.gets.max_texture_size;
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
|
||||||
return mContext.gets.max_cubemap_texture_size;
|
|
||||||
case SamplerType::SAMPLER_3D:
|
|
||||||
return mContext.gets.max_3d_texture_size;
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
|
||||||
return mContext.gets.max_cubemap_texture_size;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t OpenGLDriver::getMaxArrayTextureLayers() {
|
|
||||||
return mContext.gets.max_array_texture_layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Swap chains
|
// Swap chains
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ OpenGLProgram::~OpenGLProgram() noexcept {
|
|||||||
delete lazyInitializationData;
|
delete lazyInitializationData;
|
||||||
|
|
||||||
ShaderCompilerService::terminate(mToken);
|
ShaderCompilerService::terminate(mToken);
|
||||||
assert_invariant(!mToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] mUniformsRecords;
|
delete [] mUniformsRecords;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,23 +24,23 @@
|
|||||||
#include "OpenGLBlobCache.h"
|
#include "OpenGLBlobCache.h"
|
||||||
|
|
||||||
#include <backend/CallbackHandler.h>
|
#include <backend/CallbackHandler.h>
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
|
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
#include <utils/Invocable.h>
|
||||||
#include <utils/JobSystem.h>
|
#include <utils/JobSystem.h>
|
||||||
|
|
||||||
#include <array>
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <tuple>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
class OpenGLDriver;
|
class OpenGLDriver;
|
||||||
@@ -57,8 +57,6 @@ class ShaderCompilerService {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
using program_token_t = std::shared_ptr<OpenGLProgramToken>;
|
using program_token_t = std::shared_ptr<OpenGLProgramToken>;
|
||||||
using shaders_t = std::array<GLuint, Program::SHADER_TYPE_COUNT>;
|
|
||||||
using shaders_source_t = std::array<utils::CString, Program::SHADER_TYPE_COUNT>;
|
|
||||||
|
|
||||||
explicit ShaderCompilerService(OpenGLDriver& driver);
|
explicit ShaderCompilerService(OpenGLDriver& driver);
|
||||||
|
|
||||||
@@ -84,7 +82,6 @@ public:
|
|||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
// Destroys a valid token and all associated resources. Used to "cancel" a program compilation.
|
// Destroys a valid token and all associated resources. Used to "cancel" a program compilation.
|
||||||
// This function is not called if `initialize(token)` is already invoked.
|
|
||||||
static void terminate(program_token_t& token);
|
static void terminate(program_token_t& token);
|
||||||
|
|
||||||
// stores a user data pointer in the token
|
// stores a user data pointer in the token
|
||||||
@@ -93,12 +90,6 @@ public:
|
|||||||
// retrieves the user data pointer stored in the token
|
// retrieves the user data pointer stored in the token
|
||||||
static void* getUserData(const program_token_t& token) noexcept;
|
static void* getUserData(const program_token_t& token) noexcept;
|
||||||
|
|
||||||
// Issue one callback handle.
|
|
||||||
CallbackManager::Handle issueCallbackHandle() const noexcept;
|
|
||||||
|
|
||||||
// Return a callback handle to the callback manager.
|
|
||||||
void submitCallbackHandle(CallbackManager::Handle handle) noexcept;
|
|
||||||
|
|
||||||
// call the callback when all active programs are ready
|
// call the callback when all active programs are ready
|
||||||
void notifyWhenAllProgramsAreReady(
|
void notifyWhenAllProgramsAreReady(
|
||||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user);
|
CallbackHandler* handler, CallbackHandler::Callback callback, void* user);
|
||||||
@@ -106,7 +97,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
struct Job {
|
struct Job {
|
||||||
template<typename FUNC>
|
template<typename FUNC>
|
||||||
Job(FUNC&& fn) : fn(std::forward<FUNC>(fn)) {} // NOLINT(*-explicit-constructor)
|
Job(FUNC&& fn) : fn(std::forward<FUNC>(fn)) {}
|
||||||
Job(std::function<bool(Job const& job)> fn,
|
Job(std::function<bool(Job const& job)> fn,
|
||||||
CallbackHandler* handler, void* user, CallbackHandler::Callback callback)
|
CallbackHandler* handler, void* user, CallbackHandler::Callback callback)
|
||||||
: fn(std::move(fn)), handler(handler), user(user), callback(callback) {
|
: fn(std::move(fn)), handler(handler), user(user), callback(callback) {
|
||||||
@@ -135,49 +126,39 @@ private:
|
|||||||
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
|
using ContainerType = std::tuple<CompilerPriorityQueue, program_token_t, Job>;
|
||||||
std::vector<ContainerType> mRunAtNextTickOps;
|
std::vector<ContainerType> mRunAtNextTickOps;
|
||||||
|
|
||||||
GLuint initialize(program_token_t& token);
|
GLuint initialize(ShaderCompilerService::program_token_t& token) noexcept;
|
||||||
void ensureTokenIsReady(program_token_t const& token);
|
|
||||||
|
|
||||||
void runAtNextTick(CompilerPriorityQueue priority, program_token_t const& token,
|
static void getProgramFromCompilerPool(program_token_t& token) noexcept;
|
||||||
Job job) noexcept;
|
|
||||||
|
static void compileShaders(
|
||||||
|
OpenGLContext& context,
|
||||||
|
Program::ShaderSource shadersSource,
|
||||||
|
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
||||||
|
bool multiview,
|
||||||
|
std::array<GLuint, Program::SHADER_TYPE_COUNT>& outShaders,
|
||||||
|
std::array<utils::CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept;
|
||||||
|
|
||||||
|
static void process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
|
||||||
|
char* source, size_t len) noexcept;
|
||||||
|
|
||||||
|
static void process_OVR_multiview2(OpenGLContext& context, int32_t eyeCount,
|
||||||
|
char* source, size_t len) noexcept;
|
||||||
|
|
||||||
|
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
|
||||||
|
|
||||||
|
static std::array<std::string_view, 3> splitShaderSource(std::string_view source) noexcept;
|
||||||
|
|
||||||
|
static GLuint linkProgram(OpenGLContext& context,
|
||||||
|
std::array<GLuint, Program::SHADER_TYPE_COUNT> shaders,
|
||||||
|
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> const& attributes) noexcept;
|
||||||
|
|
||||||
|
static bool checkProgramStatus(program_token_t const& token) noexcept;
|
||||||
|
|
||||||
|
void runAtNextTick(CompilerPriorityQueue priority,
|
||||||
|
const program_token_t& token, Job job) noexcept;
|
||||||
void executeTickOps() noexcept;
|
void executeTickOps() noexcept;
|
||||||
bool cancelTickOp(program_token_t const& token) noexcept;
|
bool cancelTickOp(program_token_t token) noexcept;
|
||||||
|
// order of insertion is important
|
||||||
// Compile shaders with the given `shaderSource`. `gl.shaders` is always populated with valid
|
|
||||||
// shader IDs after this method. But this doesn't necessarily mean the shaders are successfully
|
|
||||||
// compiled. Errors can be checked by calling `checkCompileStatus` later.
|
|
||||||
static void compileShaders(OpenGLContext& context, Program::ShaderSource shadersSource,
|
|
||||||
utils::FixedCapacityVector<Program::SpecializationConstant> const&
|
|
||||||
specializationConstants,
|
|
||||||
bool multiview, program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Check if the shader compilation is completed. You may want to call this when the extension
|
|
||||||
// `KHR_parallel_shader_compile` is enabled.
|
|
||||||
static bool isCompileCompleted(program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Check compilation status of the shaders and log errors on failure.
|
|
||||||
static void checkCompileStatus(program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Create a program by linking the compiled shaders. `gl.program` is always populated with a
|
|
||||||
// valid program ID after this method. But this doesn't necessarily mean the program is
|
|
||||||
// successfully linked. Errors can be checked by calling `checkLinkStatusAndCleanupShaders`
|
|
||||||
// later.
|
|
||||||
static void linkProgram(OpenGLContext const& context, program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Check if the program link is completed. You may want to call this when the extension
|
|
||||||
// `KHR_parallel_shader_compile` is enabled.
|
|
||||||
static bool isLinkCompleted(program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Check link status of the program and log errors on failure. Return the result of the link.
|
|
||||||
// Also cleanup shaders regardless of the result.
|
|
||||||
static bool checkLinkStatusAndCleanupShaders(program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Try caching the program if we haven't done it yet. Cache it only when the program is valid.
|
|
||||||
static void tryCachingProgram(OpenGLBlobCache& cache, OpenGLPlatform& platform,
|
|
||||||
program_token_t const& token) noexcept;
|
|
||||||
|
|
||||||
// Cleanup GL resources.
|
|
||||||
static void cleanupProgramAndShaders(program_token_t const& token) noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept {
|
|||||||
delete pImpl;
|
delete pImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
Driver* PlatformCocoaTouchGL::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
|
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
|
||||||
|
|
||||||
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <backend/platforms/PlatformEGL.h>
|
#include <backend/platforms/PlatformEGL.h>
|
||||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
#include <backend/platforms/PlatformEGLAndroid.h>
|
||||||
|
|
||||||
#include <private/backend/BackendUtilsAndroid.h>
|
|
||||||
#include <private/backend/VirtualMachineEnv.h>
|
#include <private/backend/VirtualMachineEnv.h>
|
||||||
|
|
||||||
#include "opengl/GLUtils.h"
|
#include "opengl/GLUtils.h"
|
||||||
@@ -35,8 +34,6 @@
|
|||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/compiler.h>
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
@@ -234,133 +231,26 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
|||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() {
|
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default;
|
||||||
if (__builtin_available(android 26, *)) {
|
|
||||||
if (aHardwareBuffer) {
|
|
||||||
AHardwareBuffer_release(aHardwareBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer,
|
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
||||||
bool sRGB) noexcept {
|
auto* const p = new(std::nothrow) ExternalImageEGLAndroid;
|
||||||
if (__builtin_available(android 26, *)) {
|
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
||||||
auto* const p = new (std::nothrow) ExternalImageEGLAndroid;
|
|
||||||
auto hardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
|
||||||
AHardwareBuffer_acquire(hardwareBuffer);
|
|
||||||
p->aHardwareBuffer = hardwareBuffer;
|
|
||||||
p->sRGB = sRGB;
|
p->sRGB = sRGB;
|
||||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
|
||||||
AHardwareBuffer_describe(hardwareBuffer, &hardwareBufferDescription);
|
|
||||||
p->height = hardwareBufferDescription.height;
|
|
||||||
p->width = hardwareBufferDescription.width;
|
|
||||||
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
|
||||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
|
||||||
return ExternalImageHandle{ p };
|
return ExternalImageHandle{ p };
|
||||||
}
|
|
||||||
|
|
||||||
return Platform::ExternalImageHandle{};
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformEGLAndroid::ExternalImageDescAndroid PlatformEGLAndroid::getExternalImageDesc(
|
|
||||||
ExternalImageHandle externalImage) noexcept {
|
|
||||||
auto const* const eglExternalImage =
|
|
||||||
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
|
||||||
ExternalImageDescAndroid metadata = {};
|
|
||||||
if (!eglExternalImage) {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
metadata.height = eglExternalImage->height;
|
|
||||||
metadata.width = eglExternalImage->width;
|
|
||||||
metadata.format = eglExternalImage->format;
|
|
||||||
metadata.usage = eglExternalImage->usage;
|
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage,
|
bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage,
|
||||||
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
||||||
auto const* const eglExternalImage =
|
auto const* const eglExternalImage = static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
||||||
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
|
||||||
if (eglExternalImage->aHardwareBuffer) {
|
if (eglExternalImage->aHardwareBuffer) {
|
||||||
return PlatformEGLAndroid::setImage(eglExternalImage, texture);
|
// TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// not a AHardwareBuffer, fallback to the inherited version
|
// not a AHardwareBuffer, fallback to the inherited version
|
||||||
return PlatformEGL::setExternalImage(externalImage, texture);
|
return PlatformEGL::setExternalImage(externalImage, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLPlatform::ExternalTexture* PlatformEGLAndroid::createExternalImageTexture() noexcept {
|
|
||||||
ExternalTexture* outTexture = new (std::nothrow) ExternalTexture{};
|
|
||||||
glGenTextures(1, &outTexture->id);
|
|
||||||
return outTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlatformEGLAndroid::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
|
|
||||||
glDeleteTextures(1, &texture->id);
|
|
||||||
delete texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImage,
|
|
||||||
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
|
||||||
AHardwareBuffer* hardwareBuffer = eglExternalImage->aHardwareBuffer;
|
|
||||||
|
|
||||||
// Get the EGL client buffer from AHardwareBuffer
|
|
||||||
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
|
|
||||||
EGLint imageAttrs[] = {
|
|
||||||
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
|
|
||||||
EGL_NONE, EGL_NONE, // Reserve space
|
|
||||||
EGL_NONE, EGL_NONE, // Reserve space
|
|
||||||
EGL_NONE // Ensure the list always ends with EGL_NONE
|
|
||||||
};
|
|
||||||
int attrIndex = 2;
|
|
||||||
if (eglExternalImage->sRGB) {
|
|
||||||
imageAttrs[attrIndex++] = EGL_GL_COLORSPACE;
|
|
||||||
imageAttrs[attrIndex++] = EGL_GL_COLORSPACE_SRGB;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<bool>(eglExternalImage->usage & TextureUsage::PROTECTED)) {
|
|
||||||
imageAttrs[attrIndex++] = EGL_PROTECTED_CONTENT_EXT;
|
|
||||||
imageAttrs[attrIndex++] = EGL_TRUE;
|
|
||||||
}
|
|
||||||
// Create an EGLImage from the client buffer
|
|
||||||
EGLImageKHR eglImage = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
|
|
||||||
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
|
|
||||||
if (eglImage == EGL_NO_IMAGE_KHR) {
|
|
||||||
// Handle error
|
|
||||||
slog.e << "Failed to create EGL image" << io::endl;
|
|
||||||
glDeleteTextures(1, &texture->id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and bind the OpenGL texture
|
|
||||||
GLint prevActiveTexture, prevTexture;
|
|
||||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &prevActiveTexture);
|
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTexture);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(texture->target, texture->id);
|
|
||||||
GLenum error = glGetError();
|
|
||||||
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
|
|
||||||
slog.e << "Error after glBindTexture: " << error << io::endl;
|
|
||||||
glDeleteTextures(1, &texture->id);
|
|
||||||
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
|
|
||||||
glActiveTexture(prevActiveTexture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
glEGLImageTargetTexture2DOES(texture->target, static_cast<GLeglImageOES>(eglImage));
|
|
||||||
error = glGetError();
|
|
||||||
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
|
|
||||||
slog.e << "Error after glEGLImageTargetTexture2DOES: " << error << io::endl;
|
|
||||||
glDeleteTextures(1, &texture->id);
|
|
||||||
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
|
|
||||||
glActiveTexture(prevActiveTexture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
glActiveTexture(prevActiveTexture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept {
|
void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept {
|
||||||
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
|
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
|
||||||
if (currentDrawSurface != EGL_NO_SURFACE) {
|
if (currentDrawSurface != EGL_NO_SURFACE) {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
Driver* PlatformGLX::createDriver(void* const sharedGLContext,
|
||||||
const DriverConfig& driverConfig) noexcept {
|
const DriverConfig& driverConfig) noexcept {
|
||||||
loadLibraries();
|
loadLibraries();
|
||||||
// Get the display device
|
// Get the display device
|
||||||
|
|||||||
@@ -22,11 +22,9 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
// This is to ensure that linking during compilation will not fail even if
|
// This is to ensure that linking during compilation will not fail even if
|
||||||
// OSMesaGetProcAddress is not linked.
|
// OSMesaGetProcAddress is not linked.
|
||||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -50,27 +48,20 @@ struct OSMesaSwapchain {
|
|||||||
|
|
||||||
struct OSMesaAPI {
|
struct OSMesaAPI {
|
||||||
private:
|
private:
|
||||||
using CreateContextAttribsFunc = OSMesaContext (*)(const int *, OSMesaContext);
|
using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext);
|
||||||
using DestroyContextFunc = GLboolean (*)(OSMesaContext);
|
using DestroyContextFunc = GLboolean (*)(OSMesaContext);
|
||||||
using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type,
|
using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type,
|
||||||
GLsizei width, GLsizei height);
|
GLsizei width, GLsizei height);
|
||||||
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CreateContextAttribsFunc fOSMesaCreateContextAttribs;
|
CreateContextFunc fOSMesaCreateContext;
|
||||||
DestroyContextFunc fOSMesaDestroyContext;
|
DestroyContextFunc fOSMesaDestroyContext;
|
||||||
MakeCurrentFunc fOSMesaMakeCurrent;
|
MakeCurrentFunc fOSMesaMakeCurrent;
|
||||||
GetProcAddressFunc fOSMesaGetProcAddress;
|
GetProcAddressFunc fOSMesaGetProcAddress;
|
||||||
|
|
||||||
OSMesaAPI() {
|
OSMesaAPI() {
|
||||||
static constexpr char const* libraryNames[] = {
|
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||||
#if defined(__linux__)
|
|
||||||
"libOSMesa.so",
|
|
||||||
"libosmesa.so",
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
"libOSMesa.dylib",
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
for (char const* libName: libraryNames) {
|
for (char const* libName: libraryNames) {
|
||||||
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
|
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
|
||||||
if (mLib) {
|
if (mLib) {
|
||||||
@@ -80,24 +71,22 @@ public:
|
|||||||
if (mLib) {
|
if (mLib) {
|
||||||
// Loading from a libosmesa.os
|
// Loading from a libosmesa.os
|
||||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||||
}
|
} else {
|
||||||
#if defined(__linux__)
|
|
||||||
else {
|
|
||||||
// Filament is built into a .so
|
// Filament is built into a .so
|
||||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fOSMesaGetProcAddress) {
|
if (!fOSMesaGetProcAddress) {
|
||||||
// Statically linking osmesa
|
// Statically linking osmesa
|
||||||
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
||||||
}
|
}
|
||||||
#endif // __linux__
|
|
||||||
|
|
||||||
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
||||||
<< "Unable to link against libOSMesa to create a software GL context";
|
<< "Unable to link against libOSMesa to create a software GL context";
|
||||||
|
|
||||||
fOSMesaCreateContextAttribs =
|
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
|
||||||
(CreateContextAttribsFunc) fOSMesaGetProcAddress("OSMesaCreateContextAttribs");
|
fOSMesaDestroyContext =
|
||||||
fOSMesaDestroyContext = (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||||
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,24 +101,14 @@ private:
|
|||||||
|
|
||||||
}// anonymous namespace
|
}// anonymous namespace
|
||||||
|
|
||||||
Driver* PlatformOSMesa::createDriver(void* sharedGLContext,
|
Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||||
const DriverConfig& driverConfig) noexcept {
|
const DriverConfig& driverConfig) noexcept {
|
||||||
|
|
||||||
OSMesaAPI* api = new OSMesaAPI();
|
OSMesaAPI* api = new OSMesaAPI();
|
||||||
mOsMesaApi = api;
|
mOsMesaApi = api;
|
||||||
|
|
||||||
static constexpr int attribs[] = {
|
|
||||||
OSMESA_FORMAT, GL_RGBA,
|
|
||||||
OSMESA_DEPTH_BITS, 24,
|
|
||||||
OSMESA_STENCIL_BITS, 8,
|
|
||||||
OSMESA_ACCUM_BITS, 0,
|
|
||||||
OSMESA_PROFILE, OSMESA_CORE_PROFILE,
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
|
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
|
||||||
<< "shared GL context is not supported with PlatformOSMesa";
|
<< "shared GL context is not supported with PlatformOSMesa";
|
||||||
mContext = api->fOSMesaCreateContextAttribs(attribs, NULL);
|
mContext = api->fOSMesaCreateContext(GL_RGBA, NULL);
|
||||||
|
|
||||||
// We need to do a no-op makecurrent here so that the context will be in a correct state before
|
// We need to do a no-op makecurrent here so that the context will be in a correct state before
|
||||||
// any GL calls.
|
// any GL calls.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ struct WGLSwapChain {
|
|||||||
|
|
||||||
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
|
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
|
||||||
|
|
||||||
Driver* PlatformWGL::createDriver(void* sharedGLContext,
|
Driver* PlatformWGL::createDriver(void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int pixelFormat = 0;
|
int pixelFormat = 0;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
Driver* PlatformWebGL::createDriver(void* sharedGLContext,
|
Driver* PlatformWebGL::createDriver(void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <backend/BufferDescriptor.h>
|
#include <backend/BufferDescriptor.h>
|
||||||
#include <backend/BufferObjectStreamDescriptor.h>
|
|
||||||
#include <backend/DescriptorSetOffsetArray.h>
|
#include <backend/DescriptorSetOffsetArray.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/PipelineState.h>
|
#include <backend/PipelineState.h>
|
||||||
@@ -438,10 +437,6 @@ io::ostream& operator<<(io::ostream& out, BufferDescriptor const& b) {
|
|||||||
<< ", user=" << b.getUser() << " }";
|
<< ", user=" << b.getUser() << " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
io::ostream& operator<<(io::ostream& out, const BufferObjectStreamDescriptor& b) {
|
|
||||||
return out << "BufferObjectStreamDescriptor{ streams(" << b.mStreams.size() << ")=... }";
|
|
||||||
}
|
|
||||||
|
|
||||||
io::ostream& operator<<(io::ostream& out, PixelBufferDescriptor const& b) {
|
io::ostream& operator<<(io::ostream& out, PixelBufferDescriptor const& b) {
|
||||||
BufferDescriptor const& base = static_cast<BufferDescriptor const&>(b);
|
BufferDescriptor const& base = static_cast<BufferDescriptor const&>(b);
|
||||||
return out << "PixelBufferDescriptor{ " << base
|
return out << "PixelBufferDescriptor{ " << base
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
#include "VulkanBlitter.h"
|
#include "VulkanBlitter.h"
|
||||||
#include "VulkanCommands.h"
|
#include "VulkanCommands.h"
|
||||||
#include "VulkanContext.h"
|
#include "VulkanContext.h"
|
||||||
|
#include "VulkanFboCache.h"
|
||||||
|
#include "VulkanHandles.h"
|
||||||
|
#include "VulkanSamplerCache.h"
|
||||||
#include "VulkanTexture.h"
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/utils/Image.h"
|
#include "vulkan/utils/Image.h"
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,13 @@
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class VulkanBuffer;
|
||||||
|
class VulkanFboCache;
|
||||||
|
class VulkanPipelineCache;
|
||||||
|
class VulkanSamplerCache;
|
||||||
|
|
||||||
|
struct VulkanProgram;
|
||||||
|
|
||||||
class VulkanBlitter {
|
class VulkanBlitter {
|
||||||
public:
|
public:
|
||||||
VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept;
|
VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept;
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
|
|||||||
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
|
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
|
||||||
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
|
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
|
||||||
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
|
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
|
||||||
#define FVK_SYSTRACE_SCOPE() SYSTRACE_CALL()
|
#define FVK_SYSTRACE_SCOPE() SYSTRACE_NAME(__func__)
|
||||||
#define FVK_PROFILE_MARKER(marker) SYSTRACE_CALL()
|
#define FVK_PROFILE_MARKER(marker) FVK_SYSTRACE_SCOPE()
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define FVK_SYSTRACE_CONTEXT()
|
#define FVK_SYSTRACE_CONTEXT()
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ VkImageView VulkanAttachment::getImageView() {
|
|||||||
assert_invariant(texture);
|
assert_invariant(texture);
|
||||||
VkImageSubresourceRange range = getSubresourceRange();
|
VkImageSubresourceRange range = getSubresourceRange();
|
||||||
if (range.layerCount > 1) {
|
if (range.layerCount > 1) {
|
||||||
return texture->getAttachmentView(range, VK_IMAGE_VIEW_TYPE_2D_ARRAY);
|
return texture->getMultiviewAttachmentView(range);
|
||||||
}
|
}
|
||||||
return texture->getAttachmentView(range, VK_IMAGE_VIEW_TYPE_2D);
|
return texture->getAttachmentView(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanAttachment::isDepth() const {
|
bool VulkanAttachment::isDepth() const {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANCONTEXT_H
|
#ifndef TNT_FILAMENT_BACKEND_VULKANCONTEXT_H
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANCONTEXT_H
|
#define TNT_FILAMENT_BACKEND_VULKANCONTEXT_H
|
||||||
|
|
||||||
|
#include "VulkanConstants.h"
|
||||||
#include "vulkan/utils/Image.h"
|
#include "vulkan/utils/Image.h"
|
||||||
#include "vulkan/utils/Definitions.h"
|
#include "vulkan/utils/Definitions.h"
|
||||||
|
|
||||||
@@ -29,6 +30,8 @@
|
|||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
VK_DEFINE_HANDLE(VmaAllocator)
|
VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
VK_DEFINE_HANDLE(VmaPool)
|
VK_DEFINE_HANDLE(VmaPool)
|
||||||
|
|
||||||
@@ -70,11 +73,13 @@ struct VulkanRenderPass {
|
|||||||
// context are stored in VulkanPlatform.
|
// context are stored in VulkanPlatform.
|
||||||
struct VulkanContext {
|
struct VulkanContext {
|
||||||
public:
|
public:
|
||||||
static uint32_t selectMemoryType(VkPhysicalDeviceMemoryProperties const& memoryProperties,
|
inline uint32_t selectMemoryType(uint32_t flags, VkFlags reqs) const {
|
||||||
uint32_t flags, VkFlags reqs) {
|
if ((reqs & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0) {
|
||||||
|
assert_invariant(isProtectedMemorySupported() == true);
|
||||||
|
}
|
||||||
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
|
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
|
||||||
if (flags & 1) {
|
if (flags & 1) {
|
||||||
if ((memoryProperties.memoryTypes[i].propertyFlags & reqs) == reqs) {
|
if ((mMemoryProperties.memoryTypes[i].propertyFlags & reqs) == reqs) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,13 +88,6 @@ public:
|
|||||||
return (uint32_t) VK_MAX_MEMORY_TYPES;
|
return (uint32_t) VK_MAX_MEMORY_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t selectMemoryType(uint32_t flags, VkFlags reqs) const {
|
|
||||||
if ((reqs & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0) {
|
|
||||||
assert_invariant(isProtectedMemorySupported());
|
|
||||||
}
|
|
||||||
return selectMemoryType(mMemoryProperties, flags, reqs);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
|
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
|
||||||
return mDepthStencilFormats;
|
return mDepthStencilFormats;
|
||||||
}
|
}
|
||||||
@@ -123,7 +121,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool isMultiviewEnabled() const noexcept {
|
inline bool isMultiviewEnabled() const noexcept {
|
||||||
return mPhysicalDeviceVk11Features.multiview == VK_TRUE;
|
return mMultiviewEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isClipDistanceSupported() const noexcept {
|
inline bool isClipDistanceSupported() const noexcept {
|
||||||
@@ -147,9 +145,6 @@ private:
|
|||||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||||
};
|
};
|
||||||
VkPhysicalDeviceVulkan11Features mPhysicalDeviceVk11Features = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
|
|
||||||
};
|
|
||||||
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
|
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||||
};
|
};
|
||||||
@@ -162,6 +157,7 @@ private:
|
|||||||
};
|
};
|
||||||
bool mDebugMarkersSupported = false;
|
bool mDebugMarkersSupported = false;
|
||||||
bool mDebugUtilsSupported = false;
|
bool mDebugUtilsSupported = false;
|
||||||
|
bool mMultiviewEnabled = false;
|
||||||
bool mLazilyAllocatedMemorySupported = false;
|
bool mLazilyAllocatedMemorySupported = false;
|
||||||
bool mProtectedMemorySupported = false;
|
bool mProtectedMemorySupported = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,416 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "VulkanDescriptorSetCache.h"
|
|
||||||
|
|
||||||
#include "VulkanCommands.h"
|
|
||||||
#include "VulkanHandles.h"
|
|
||||||
#include "VulkanConstants.h"
|
|
||||||
|
|
||||||
#include <utils/FixedCapacityVector.h>
|
|
||||||
#include <utils/Panic.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using DescriptorCount = VulkanDescriptorSetLayout::Count;
|
|
||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
|
|
||||||
|
|
||||||
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
|
||||||
// example, a layout of
|
|
||||||
// 'A' =>
|
|
||||||
// layout(binding = 0, set = 1) uniform {};
|
|
||||||
// layout(binding = 1, set = 1) sampler1;
|
|
||||||
// layout(binding = 2, set = 1) sampler2;
|
|
||||||
//
|
|
||||||
// would be equivalent to
|
|
||||||
// 'B' =>
|
|
||||||
// layout(binding = 1, set = 2) uniform {};
|
|
||||||
// layout(binding = 2, set = 2) sampler2;
|
|
||||||
// layout(binding = 3, set = 2) sampler3;
|
|
||||||
//
|
|
||||||
// TODO: we might do better if we understand the types of unique layouts and can combine them in a
|
|
||||||
// single pool without too much waste.
|
|
||||||
class DescriptorPool {
|
|
||||||
public:
|
|
||||||
DescriptorPool(VkDevice device, DescriptorCount const& count, uint16_t capacity)
|
|
||||||
: mDevice(device),
|
|
||||||
mCount(count),
|
|
||||||
mCapacity(capacity),
|
|
||||||
mSize(0),
|
|
||||||
mUnusedCount(0) {
|
|
||||||
DescriptorCount const actual = mCount * capacity;
|
|
||||||
VkDescriptorPoolSize sizes[4];
|
|
||||||
uint8_t npools = 0;
|
|
||||||
if (actual.ubo) {
|
|
||||||
sizes[npools++] = {
|
|
||||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
||||||
.descriptorCount = actual.ubo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (actual.dynamicUbo) {
|
|
||||||
sizes[npools++] = {
|
|
||||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
|
||||||
.descriptorCount = actual.dynamicUbo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (actual.sampler) {
|
|
||||||
sizes[npools++] = {
|
|
||||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
.descriptorCount = actual.sampler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (actual.inputAttachment) {
|
|
||||||
sizes[npools++] = {
|
|
||||||
.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
||||||
.descriptorCount = actual.inputAttachment,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
VkDescriptorPoolCreateInfo info{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.maxSets = capacity,
|
|
||||||
.poolSizeCount = npools,
|
|
||||||
.pPoolSizes = sizes,
|
|
||||||
};
|
|
||||||
vkCreateDescriptorPool(mDevice, &info, VKALLOC, &mPool);
|
|
||||||
}
|
|
||||||
|
|
||||||
DescriptorPool(DescriptorPool const&) = delete;
|
|
||||||
DescriptorPool& operator=(DescriptorPool const&) = delete;
|
|
||||||
|
|
||||||
~DescriptorPool() {
|
|
||||||
vkDestroyDescriptorPool(mDevice, mPool, VKALLOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t const& capacity() {
|
|
||||||
return mCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A convenience method for checking if this pool can allocate sets for a given layout.
|
|
||||||
inline bool canAllocate(DescriptorCount const& count) {
|
|
||||||
return count == mCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSet obtainSet(VkDescriptorSetLayout vklayout) {
|
|
||||||
auto itr = findSets(vklayout);
|
|
||||||
if (itr != mUnused.end()) {
|
|
||||||
// If we don't have any unused, then just return an empty handle.
|
|
||||||
if (itr->second.empty()) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
std::vector<VkDescriptorSet>& sets = itr->second;
|
|
||||||
auto set = sets.back();
|
|
||||||
sets.pop_back();
|
|
||||||
mUnusedCount--;
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
if (mSize + 1 > mCapacity) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
// Creating a new set
|
|
||||||
VkDescriptorSetLayout layouts[1] = {vklayout};
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.descriptorPool = mPool,
|
|
||||||
.descriptorSetCount = 1,
|
|
||||||
.pSetLayouts = layouts,
|
|
||||||
};
|
|
||||||
VkDescriptorSet vkSet;
|
|
||||||
UTILS_UNUSED VkResult result = vkAllocateDescriptorSets(mDevice, &allocInfo, &vkSet);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Failed to allocate descriptor set code=" << result << " size=" << mSize
|
|
||||||
<< " capacity=" << mCapacity << " count=" << mUnusedCount;
|
|
||||||
mSize++;
|
|
||||||
return vkSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void recycle(VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
|
||||||
// We are recycling - release the set back into the pool. Note that the
|
|
||||||
// vk handle has not changed, but we need to change the backend handle to allow
|
|
||||||
// for proper refcounting of resources referenced in this set.
|
|
||||||
auto itr = findSets(vklayout);
|
|
||||||
if (itr != mUnused.end()) {
|
|
||||||
itr->second.push_back(vkSet);
|
|
||||||
} else {
|
|
||||||
mUnused.push_back(std::make_pair(vklayout, std::vector<VkDescriptorSet> {vkSet}));
|
|
||||||
}
|
|
||||||
mUnusedCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
using UnusedSets = std::pair<VkDescriptorSetLayout, std::vector<VkDescriptorSet>>;
|
|
||||||
using UnusedSetMap = std::vector<UnusedSets>;
|
|
||||||
|
|
||||||
inline UnusedSetMap::iterator findSets(VkDescriptorSetLayout vklayout) {
|
|
||||||
return std::find_if(mUnused.begin(), mUnused.end(), [vklayout](auto const& value) {
|
|
||||||
return value.first == vklayout;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDevice mDevice;
|
|
||||||
VkDescriptorPool mPool;
|
|
||||||
DescriptorCount const mCount;
|
|
||||||
uint16_t const mCapacity;
|
|
||||||
|
|
||||||
// Tracks the number of allocated descriptor sets.
|
|
||||||
uint16_t mSize;
|
|
||||||
// Tracks the number of in-use descriptor sets.
|
|
||||||
uint16_t mUnusedCount;
|
|
||||||
|
|
||||||
// This maps a layout to a list of descriptor sets allocated for that layout.
|
|
||||||
UnusedSetMap mUnused;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Key>
|
|
||||||
struct Equal {
|
|
||||||
bool operator()(Key const& k1, Key const& k2) const {
|
|
||||||
return 0 == memcmp((const void*) &k1, (const void*) &k2, sizeof(Key));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
// This is an ever-expanding pool of sets where it
|
|
||||||
// 1. Keeps a list of smaller pools of different layout-dimensions.
|
|
||||||
// 2. Will add a pool if existing pool are not compatible with the requested layout o runs out.
|
|
||||||
class VulkanDescriptorSetCache::DescriptorInfinitePool {
|
|
||||||
private:
|
|
||||||
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
|
|
||||||
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DescriptorInfinitePool(VkDevice device)
|
|
||||||
: mDevice(device) {}
|
|
||||||
|
|
||||||
VkDescriptorSet obtainSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
|
||||||
auto const vklayout = layout->getVkLayout();
|
|
||||||
DescriptorPool* sameTypePool = nullptr;
|
|
||||||
for (auto& pool: mPools) {
|
|
||||||
if (!pool->canAllocate(layout->count)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) {
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
if (!sameTypePool || sameTypePool->capacity() < pool->capacity()) {
|
|
||||||
sameTypePool = pool.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t capacity = EXPECTED_SET_COUNT;
|
|
||||||
if (sameTypePool) {
|
|
||||||
// Exponentially increase the size of the pool to ensure we don't hit this too often.
|
|
||||||
capacity = std::ceil(sameTypePool->capacity() * SET_COUNT_GROWTH_FACTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to increase the set of pools by one.
|
|
||||||
mPools.push_back(std::make_unique<DescriptorPool>(mDevice,
|
|
||||||
DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity));
|
|
||||||
auto& pool = mPools.back();
|
|
||||||
auto ret = pool->obtainSet(vklayout);
|
|
||||||
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void recycle(DescriptorCount const& count, VkDescriptorSetLayout vklayout,
|
|
||||||
VkDescriptorSet vkSet) {
|
|
||||||
for (auto& pool: mPools) {
|
|
||||||
if (!pool->canAllocate(count)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pool->recycle(vklayout, vkSet);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDevice mDevice;
|
|
||||||
std::vector<std::unique_ptr<DescriptorPool>> mPools;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VulkanDescriptorSetCache::VulkanDescriptorSetCache(VkDevice device,
|
|
||||||
fvkmemory::ResourceManager* resourceManager)
|
|
||||||
: mDevice(device),
|
|
||||||
mResourceManager(resourceManager),
|
|
||||||
mDescriptorPool(std::make_unique<DescriptorInfinitePool>(device)) {}
|
|
||||||
|
|
||||||
VulkanDescriptorSetCache::~VulkanDescriptorSetCache() = default;
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::terminate() noexcept{
|
|
||||||
mDescriptorPool.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind() is not really binding the set but just stashing until we have all the info
|
|
||||||
// (pipelinelayout).
|
|
||||||
void VulkanDescriptorSetCache::bind(uint8_t setIndex,
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
|
||||||
set->setOffsets(std::move(offsets));
|
|
||||||
mStashedSets[setIndex] = set;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
|
|
||||||
mStashedSets[setIndex] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
|
||||||
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
|
|
||||||
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
|
||||||
// actual set of sets that *needs* to be bound.
|
|
||||||
fvkutils::DescriptorSetMask curMask = setMask;
|
|
||||||
|
|
||||||
auto& updateSets = mStashedSets;
|
|
||||||
bool const pipelineLayoutIsSame = mLastBoundInfo.pipelineLayout == pipelineLayout;
|
|
||||||
|
|
||||||
if (pipelineLayoutIsSame) {
|
|
||||||
auto& lastBoundSets = mLastBoundInfo.boundSets;
|
|
||||||
setMask.forEachSetBit([&](size_t index) {
|
|
||||||
if (!updateSets[index] || updateSets[index] == lastBoundSets[index]) {
|
|
||||||
curMask.unset(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (curMask.none() &&
|
|
||||||
mLastBoundInfo.setMask == setMask && mLastBoundInfo.boundSets == updateSets) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setMask.forEachSetBit([&](size_t index) {
|
|
||||||
if (!updateSets[index]) {
|
|
||||||
curMask.unset(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) {
|
|
||||||
// This code actually binds the descriptor sets.
|
|
||||||
auto set = updateSets[index];
|
|
||||||
VkCommandBuffer const cmdbuffer = commands->buffer();
|
|
||||||
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
|
|
||||||
1, &set->getVkSet(), set->uniqueDynamicUboCount, set->getOffsets()->data());
|
|
||||||
commands->acquire(set);
|
|
||||||
});
|
|
||||||
|
|
||||||
mStashedSets = {};
|
|
||||||
|
|
||||||
mLastBoundInfo = {
|
|
||||||
pipelineLayout,
|
|
||||||
setMask,
|
|
||||||
updateSets,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
|
|
||||||
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
|
||||||
VkDescriptorBufferInfo const info = {
|
|
||||||
.buffer = bufferObject->buffer.getGpuBuffer(),
|
|
||||||
.offset = offset,
|
|
||||||
.range = size,
|
|
||||||
};
|
|
||||||
VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
|
|
||||||
if (set->dynamicUboMask.test(binding)) {
|
|
||||||
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
|
||||||
}
|
|
||||||
VkWriteDescriptorSet const descriptorWrite = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
||||||
.dstSet = set->getVkSet(),
|
|
||||||
.dstBinding = binding,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = type,
|
|
||||||
.pBufferInfo = &info,
|
|
||||||
};
|
|
||||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
|
||||||
set->acquire(bufferObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
|
||||||
VkSampler sampler) noexcept {
|
|
||||||
VkImageSubresourceRange range = texture->getPrimaryViewRange();
|
|
||||||
VkImageViewType const expectedType = texture->getViewType();
|
|
||||||
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
|
|
||||||
expectedType == VK_IMAGE_VIEW_TYPE_2D) {
|
|
||||||
// If the sampler is part of a mipmapped depth texture, where one of the level *can* be
|
|
||||||
// an attachment, then the range for this view has exactly one level and one layer.
|
|
||||||
range.levelCount = 1;
|
|
||||||
range.layerCount = 1;
|
|
||||||
}
|
|
||||||
VkDescriptorImageInfo info{
|
|
||||||
.sampler = sampler,
|
|
||||||
.imageView = texture->getView(range),
|
|
||||||
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
|
|
||||||
};
|
|
||||||
|
|
||||||
VkWriteDescriptorSet const descriptorWrite = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.dstSet = set->getVkSet(),
|
|
||||||
.dstBinding = binding,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
.pImageInfo = &info,
|
|
||||||
};
|
|
||||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
|
||||||
set->acquire(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateInputAttachment(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
VulkanAttachment const& attachment) noexcept {
|
|
||||||
// TOOD: fill this in.
|
|
||||||
}
|
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
|
|
||||||
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
|
||||||
auto const vkSet = getVkSet(layout);
|
|
||||||
auto const& count = layout->count;
|
|
||||||
auto const vklayout = layout->getVkLayout();
|
|
||||||
auto set = fvkmemory::resource_ptr<VulkanDescriptorSet>::make(mResourceManager, handle,
|
|
||||||
layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
|
|
||||||
[vkSet, count, vklayout, this](VulkanDescriptorSet*) {
|
|
||||||
// Note that mDescriptorPool could be gone due to terminate (when the backend shuts
|
|
||||||
// down).
|
|
||||||
if (mDescriptorPool) {
|
|
||||||
mDescriptorPool->recycle(count, vklayout, vkSet);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
set->setVkSet(vkSet);
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSet VulkanDescriptorSetCache::getVkSet(
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
|
||||||
return mDescriptorPool->obtainSet(layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::manualRecyle(VulkanDescriptorSetLayout::Count const& count,
|
|
||||||
VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
|
||||||
mDescriptorPool->recycle(count, vklayout, vkSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::gc() { mStashedSets = {}; }
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
|
||||||
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/Program.h>
|
|
||||||
#include <backend/TargetBufferInfo.h>
|
|
||||||
|
|
||||||
#include <utils/bitset.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
|
||||||
#include <tsl/robin_map.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
// Abstraction over the descriptor set pool.
|
|
||||||
class VulkanDescriptorSetCache {
|
|
||||||
public:
|
|
||||||
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
|
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
|
|
||||||
|
|
||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
|
||||||
using DescriptorSetArray =
|
|
||||||
std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>;
|
|
||||||
|
|
||||||
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
|
||||||
~VulkanDescriptorSetCache();
|
|
||||||
|
|
||||||
void terminate() noexcept;
|
|
||||||
|
|
||||||
void updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
|
||||||
fvkmemory::resource_ptr<VulkanBufferObject> bufferObject, VkDeviceSize offset,
|
|
||||||
VkDeviceSize size) noexcept;
|
|
||||||
|
|
||||||
void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
|
|
||||||
|
|
||||||
void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
VulkanAttachment const& attachment) noexcept;
|
|
||||||
|
|
||||||
void bind(uint8_t setIndex, fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
|
||||||
backend::DescriptorSetOffsetArray&& offsets);
|
|
||||||
|
|
||||||
void unbind(uint8_t setIndex);
|
|
||||||
|
|
||||||
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
|
|
||||||
fvkutils::DescriptorSetMask const& setMask);
|
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
|
||||||
|
|
||||||
// This method is only meant to be used with external samplers (or internally within this
|
|
||||||
// class).
|
|
||||||
VkDescriptorSet getVkSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
|
||||||
|
|
||||||
// This method is only meant to be used with external samplers.
|
|
||||||
void manualRecyle(VulkanDescriptorSetLayout::Count const& count, VkDescriptorSetLayout vklayout,
|
|
||||||
VkDescriptorSet vkSet);
|
|
||||||
|
|
||||||
DescriptorSetArray const& getBoundSets() const { return mStashedSets; }
|
|
||||||
|
|
||||||
void gc();
|
|
||||||
|
|
||||||
private:
|
|
||||||
class DescriptorInfinitePool;
|
|
||||||
|
|
||||||
VkDevice mDevice;
|
|
||||||
fvkmemory::ResourceManager* mResourceManager;
|
|
||||||
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
|
|
||||||
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
|
||||||
DescriptorSetArray mStashedSets = {};
|
|
||||||
|
|
||||||
struct {
|
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
fvkutils::DescriptorSetMask setMask;
|
|
||||||
DescriptorSetArray boundSets = {};
|
|
||||||
} mLastBoundInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "VulkanDescriptorSetLayoutCache.h"
|
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
|
|
||||||
|
|
||||||
template<typename Bitmask>
|
|
||||||
uint32_t appendBindings(VkDescriptorSetLayoutBinding* toBind, VkDescriptorType type,
|
|
||||||
Bitmask const& mask) {
|
|
||||||
uint32_t count = 0;
|
|
||||||
Bitmask alreadySeen;
|
|
||||||
mask.forEachSetBit([&](size_t index) {
|
|
||||||
VkShaderStageFlags stages = 0;
|
|
||||||
uint32_t binding = 0;
|
|
||||||
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
|
|
||||||
binding = (uint32_t) index;
|
|
||||||
stages |= VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
|
|
||||||
if (mask.test(fragIndex)) {
|
|
||||||
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
alreadySeen.set(fragIndex);
|
|
||||||
}
|
|
||||||
} else if (!alreadySeen.test(index)) {
|
|
||||||
// We are in fragment stage bits
|
|
||||||
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
|
|
||||||
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stages) {
|
|
||||||
toBind[count++] = {
|
|
||||||
.binding = binding,
|
|
||||||
.descriptorType = type,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = stages,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t appendSamplerBindings(VkDescriptorSetLayoutBinding* toBind,
|
|
||||||
fvkutils::SamplerBitmask const& mask, fvkutils::SamplerBitmask const& external,
|
|
||||||
utils::FixedCapacityVector<VkSampler> const& immutableSamplers) {
|
|
||||||
using Bitmask = fvkutils::SamplerBitmask;
|
|
||||||
uint32_t count = 0;
|
|
||||||
Bitmask alreadySeen;
|
|
||||||
uint8_t immutableIndex = 0;
|
|
||||||
size_t const immutableSamplerCount = immutableSamplers.size();
|
|
||||||
mask.forEachSetBit([&](size_t index) {
|
|
||||||
VkShaderStageFlags stages = 0;
|
|
||||||
uint32_t binding = 0;
|
|
||||||
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
|
|
||||||
binding = (uint32_t) index;
|
|
||||||
stages |= VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
|
|
||||||
if (mask.test(fragIndex)) {
|
|
||||||
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
alreadySeen.set(fragIndex);
|
|
||||||
}
|
|
||||||
} else if (!alreadySeen.test(index)) {
|
|
||||||
// We are in fragment stage bits
|
|
||||||
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
|
|
||||||
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stages) {
|
|
||||||
toBind[count++] = {
|
|
||||||
.binding = binding,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = stages,
|
|
||||||
.pImmutableSamplers = external[index] && immutableSamplerCount > immutableIndex
|
|
||||||
? &immutableSamplers[immutableIndex++]
|
|
||||||
: nullptr,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t computeImmutableSamplerHash(utils::FixedCapacityVector<VkSampler> const& samplers) {
|
|
||||||
size_t const size = samplers.size();
|
|
||||||
if (size == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (size == 1) {
|
|
||||||
return (uint64_t) samplers[0];
|
|
||||||
}
|
|
||||||
return utils::hash::murmur3((uint32_t*) samplers.data(), samplers.size() * 2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
VulkanDescriptorSetLayoutCache::VulkanDescriptorSetLayoutCache(VkDevice device,
|
|
||||||
fvkmemory::ResourceManager* resourceManager)
|
|
||||||
: mDevice(device),
|
|
||||||
mResourceManager(resourceManager) {}
|
|
||||||
|
|
||||||
VulkanDescriptorSetLayoutCache::~VulkanDescriptorSetLayoutCache() = default;
|
|
||||||
|
|
||||||
void VulkanDescriptorSetLayoutCache::terminate() noexcept {
|
|
||||||
for (auto& itr: mVkLayouts) {
|
|
||||||
vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
|
||||||
VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
|
||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers) {
|
|
||||||
LayoutKey key = {
|
|
||||||
.bitmask = bitmasks,
|
|
||||||
.immutableSamplerHash = computeImmutableSamplerHash(immutableSamplers),
|
|
||||||
};
|
|
||||||
if (auto itr = mVkLayouts.find(key); itr != mVkLayouts.end()) {
|
|
||||||
return itr->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS];
|
|
||||||
uint32_t count = 0;
|
|
||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
|
||||||
bitmasks.dynamicUbo);
|
|
||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo);
|
|
||||||
count += appendSamplerBindings(&toBind[count], bitmasks.sampler, bitmasks.externalSampler,
|
|
||||||
immutableSamplers);
|
|
||||||
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
||||||
bitmasks.inputAttachment);
|
|
||||||
|
|
||||||
assert_invariant(count != 0 && "Need at least one binding for descriptor set layout.");
|
|
||||||
VkDescriptorSetLayoutCreateInfo dlinfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
||||||
.bindingCount = count,
|
|
||||||
.pBindings = toBind,
|
|
||||||
};
|
|
||||||
VkDescriptorSetLayout vklayout;
|
|
||||||
vkCreateDescriptorSetLayout(mDevice, &dlinfo, VKALLOC, &vklayout);
|
|
||||||
mVkLayouts[key] = vklayout;
|
|
||||||
return vklayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout(
|
|
||||||
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) {
|
|
||||||
auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle,
|
|
||||||
info);
|
|
||||||
layout->setVkLayout(getVkLayout(layout->bitmask));
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
|
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
|
||||||
|
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/Program.h>
|
|
||||||
#include <backend/TargetBufferInfo.h>
|
|
||||||
|
|
||||||
#include <utils/bitset.h>
|
|
||||||
#include <utils/FixedCapacityVector.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
|
||||||
#include <tsl/robin_map.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
class VulkanDescriptorSetLayoutCache {
|
|
||||||
public:
|
|
||||||
VulkanDescriptorSetLayoutCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
|
||||||
~VulkanDescriptorSetLayoutCache();
|
|
||||||
|
|
||||||
void terminate() noexcept;
|
|
||||||
|
|
||||||
// Just a wrapper around getVkLayout()
|
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> createLayout(
|
|
||||||
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info);
|
|
||||||
|
|
||||||
// This method is meant to be used with external samplers
|
|
||||||
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
|
||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDevice mDevice;
|
|
||||||
fvkmemory::ResourceManager* mResourceManager;
|
|
||||||
|
|
||||||
struct LayoutKey {
|
|
||||||
// this describes the layout using bitset.
|
|
||||||
VulkanDescriptorSetLayout::Bitmask bitmask = {};
|
|
||||||
// number of immutable samplers can be arbitrary; so we hash them into 64-bit.
|
|
||||||
uint64_t immutableSamplerHash = 0;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(LayoutKey) == 48);
|
|
||||||
|
|
||||||
using LayoutKeyHashFn = utils::hash::MurmurHashFn<LayoutKey>;
|
|
||||||
struct LayoutKeyEqual {
|
|
||||||
bool operator()(LayoutKey const& k1, LayoutKey const& k2) const {
|
|
||||||
return k1.bitmask == k2.bitmask && k1.immutableSamplerHash == k2.immutableSamplerHash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tsl::robin_map<LayoutKey, VkDescriptorSetLayout, LayoutKeyHashFn, LayoutKeyEqual> mVkLayouts;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
|
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "VulkanDriver.h"
|
#include "VulkanDriver.h"
|
||||||
|
|
||||||
#include "CommandStreamDispatcher.h"
|
#include "CommandStreamDispatcher.h"
|
||||||
|
#include "DataReshaper.h"
|
||||||
#include "SystraceProfile.h"
|
#include "SystraceProfile.h"
|
||||||
#include "VulkanAsyncHandles.h"
|
#include "VulkanAsyncHandles.h"
|
||||||
#include "VulkanBuffer.h"
|
#include "VulkanBuffer.h"
|
||||||
@@ -25,17 +26,16 @@
|
|||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
#include "VulkanMemory.h"
|
#include "VulkanMemory.h"
|
||||||
#include "VulkanTexture.h"
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/VulkanSamplerCache.h"
|
|
||||||
#include "vulkan/memory/ResourceManager.h"
|
#include "vulkan/memory/ResourceManager.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
#include "vulkan/utils/Definitions.h"
|
#include "vulkan/utils/Definitions.h"
|
||||||
#include "vulkan/vulkan_core.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
|
using utils::FixedCapacityVector;
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
||||||
// to a stack-allocated variable.
|
// to a stack-allocated variable.
|
||||||
@@ -214,12 +216,10 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
|
|||||||
mPipelineCache(mPlatform->getDevice()),
|
mPipelineCache(mPlatform->getDevice()),
|
||||||
mStagePool(mAllocator, &mCommands),
|
mStagePool(mAllocator, &mCommands),
|
||||||
mFramebufferCache(mPlatform->getDevice()),
|
mFramebufferCache(mPlatform->getDevice()),
|
||||||
mYcbcrConversionCache(mPlatform->getDevice()),
|
|
||||||
mSamplerCache(mPlatform->getDevice()),
|
mSamplerCache(mPlatform->getDevice()),
|
||||||
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
||||||
mReadPixels(mPlatform->getDevice()),
|
mReadPixels(mPlatform->getDevice()),
|
||||||
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager),
|
||||||
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
|
||||||
mQueryManager(mPlatform->getDevice()),
|
mQueryManager(mPlatform->getDevice()),
|
||||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||||
@@ -327,10 +327,9 @@ void VulkanDriver::terminate() {
|
|||||||
|
|
||||||
mStagePool.terminate();
|
mStagePool.terminate();
|
||||||
mPipelineCache.terminate();
|
mPipelineCache.terminate();
|
||||||
mFramebufferCache.terminate();
|
mFramebufferCache.reset();
|
||||||
mSamplerCache.terminate();
|
mSamplerCache.terminate();
|
||||||
mDescriptorSetLayoutCache.terminate();
|
mDescriptorSetManager.terminate();
|
||||||
mDescriptorSetCache.terminate();
|
|
||||||
mPipelineLayoutCache.terminate();
|
mPipelineLayoutCache.terminate();
|
||||||
|
|
||||||
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
|
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
|
||||||
@@ -366,7 +365,7 @@ void VulkanDriver::collectGarbage() {
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
// Command buffers need to be submitted and completed before other resources can be gc'd.
|
// Command buffers need to be submitted and completed before other resources can be gc'd.
|
||||||
mCommands.gc();
|
mCommands.gc();
|
||||||
mDescriptorSetCache.gc();
|
mDescriptorSetManager.clearHistory();
|
||||||
mStagePool.gc();
|
mStagePool.gc();
|
||||||
mFramebufferCache.gc();
|
mFramebufferCache.gc();
|
||||||
mPipelineCache.gc();
|
mPipelineCache.gc();
|
||||||
@@ -409,7 +408,7 @@ void VulkanDriver::updateDescriptorSetBuffer(
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
auto buffer = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
auto buffer = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
||||||
mDescriptorSetCache.updateBuffer(set, binding, buffer, offset, size);
|
mDescriptorSetManager.updateBuffer(set, binding, buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::updateDescriptorSetTexture(
|
void VulkanDriver::updateDescriptorSetTexture(
|
||||||
@@ -421,12 +420,8 @@ void VulkanDriver::updateDescriptorSetTexture(
|
|||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
||||||
|
|
||||||
// TODO: YcbcrConversion?
|
VkSampler const vksampler = mSamplerCache.getSampler(params);
|
||||||
VulkanSamplerCache::Params cacheParams = {
|
mDescriptorSetManager.updateSampler(set, binding, texture, vksampler);
|
||||||
.sampler = params,
|
|
||||||
};
|
|
||||||
VkSampler const vksampler = mSamplerCache.getSampler(cacheParams);
|
|
||||||
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::flush(int) {
|
void VulkanDriver::flush(int) {
|
||||||
@@ -559,45 +554,26 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
|||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::SamplerType target, backend::TextureFormat format,
|
||||||
|
uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
Platform::ExternalImageHandleRef externalImage) {
|
Platform::ExternalImageHandleRef externalImage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
auto const& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
|
||||||
|
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||||
if (metadata.isProtected) {
|
if (metadata.isProtected) {
|
||||||
usage |= backend::TextureUsage::PROTECTED;
|
usage |= backend::TextureUsage::PROTECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageUsageFlags vkUsage = metadata.usage;
|
|
||||||
if (any(usage & TextureUsage::BLIT_SRC)) {
|
|
||||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any(usage & (TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE))) {
|
|
||||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_invariant(width == metadata.width);
|
assert_invariant(width == metadata.width);
|
||||||
assert_invariant(height == metadata.height);
|
assert_invariant(height == metadata.height);
|
||||||
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||||
|
|
||||||
VkMemoryPropertyFlags const requiredMemoryFlags = any(usage & TextureUsage::UPLOADABLE)
|
const auto& data = mPlatform->createExternalImageData(externalImage, metadata);
|
||||||
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
||||||
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
uint32_t const memoryTypeIndex =
|
|
||||||
mContext.selectMemoryType(metadata.memoryTypeBits, requiredMemoryFlags);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex != VK_MAX_MEMORY_TYPES)
|
|
||||||
<< "failed to find a valid memory type for external image memory.";
|
|
||||||
|
|
||||||
VkImage vkimg;
|
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th,
|
||||||
VkDeviceMemory deviceMemory;
|
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||||
std::tie(vkimg, deviceMemory) =
|
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
|
||||||
mPlatform->createExternalImageData(externalImage, metadata, memoryTypeIndex, vkUsage);
|
|
||||||
|
|
||||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mContext,
|
|
||||||
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, vkimg, deviceMemory,
|
|
||||||
metadata.format, VK_NULL_HANDLE, metadata.samples, metadata.width, metadata.height,
|
|
||||||
metadata.layerCount, usage, mStagePool);
|
|
||||||
|
|
||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
@@ -606,14 +582,13 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
|
|||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* externalImage) {
|
void* externalImage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
assert_invariant(false && "Not supported in Vulkan backend");
|
|
||||||
// not supported in this backend
|
// not supported in this backend
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* image, uint32_t plane) {
|
void* image, uint32_t plane) {
|
||||||
assert_invariant(false && "Not supported in Vulkan backend");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
||||||
@@ -621,7 +596,6 @@ void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
|||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||||
TextureUsage usage) {
|
TextureUsage usage) {
|
||||||
// not supported in this backend
|
// not supported in this backend
|
||||||
assert_invariant(false && "Not supported in Vulkan backend");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
|
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
|
||||||
@@ -787,7 +761,8 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
|||||||
|
|
||||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||||
backend::DescriptorSetLayout&& info) {
|
backend::DescriptorSetLayout&& info) {
|
||||||
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
|
auto layout = resource_ptr<VulkanDescriptorSetLayout>::make(&mResourceManager, dslh, info);
|
||||||
|
mDescriptorSetManager.initVkLayout(layout);
|
||||||
layout.inc();
|
layout.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,7 +771,7 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
||||||
auto set = mDescriptorSetCache.createSet(dsh, layout);
|
auto set = mDescriptorSetManager.createSet(dsh, layout);
|
||||||
set.inc();
|
set.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,7 +1043,7 @@ bool VulkanDriver::isDepthStencilBlitSupported(TextureFormat format) {
|
|||||||
formats.end();
|
formats.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDriver::isProtectedTexturesSupported() { return isProtectedContentSupported(); }
|
bool VulkanDriver::isProtectedTexturesSupported() { return false; }
|
||||||
|
|
||||||
bool VulkanDriver::isDepthClampSupported() {
|
bool VulkanDriver::isDepthClampSupported() {
|
||||||
return mContext.isDepthClampSupported();
|
return mContext.isDepthClampSupported();
|
||||||
@@ -1145,28 +1120,14 @@ math::float2 VulkanDriver::getClipSpaceParams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t VulkanDriver::getMaxDrawBuffers() {
|
uint8_t VulkanDriver::getMaxDrawBuffers() {
|
||||||
return mContext.getPhysicalDeviceLimits().maxColorAttachments;
|
return MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; // TODO: query real value
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VulkanDriver::getMaxUniformBufferSize() {
|
size_t VulkanDriver::getMaxUniformBufferSize() {
|
||||||
return mContext.getPhysicalDeviceLimits().maxUniformBufferRange;
|
// TODO: return the actual size instead of hardcoded value
|
||||||
}
|
// TODO: devices that return less than 32768 should be rejected. This represents only 3%
|
||||||
|
// of android devices.
|
||||||
size_t VulkanDriver::getMaxTextureSize(SamplerType type) {
|
return 32768;
|
||||||
switch (type) {
|
|
||||||
case SamplerType::SAMPLER_2D:
|
|
||||||
return mContext.getPhysicalDeviceLimits().maxImageDimension2D;
|
|
||||||
case SamplerType::SAMPLER_3D:
|
|
||||||
return mContext.getPhysicalDeviceLimits().maxImageDimension3D;
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
|
||||||
return mContext.getPhysicalDeviceLimits().maxImageDimensionCube;
|
|
||||||
default:
|
|
||||||
return mContext.getPhysicalDeviceLimits().maxImageDimension1D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t VulkanDriver::getMaxArrayTextureLayers() {
|
|
||||||
return mContext.getPhysicalDeviceLimits().maxImageArrayLayers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||||
@@ -1505,7 +1466,7 @@ void VulkanDriver::nextSubpass(int) {
|
|||||||
|
|
||||||
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
||||||
VulkanAttachment& subpassInput = renderTarget->getColor0();
|
VulkanAttachment& subpassInput = renderTarget->getColor0();
|
||||||
mDescriptorSetCache.updateInputAttachment({}, subpassInput);
|
mDescriptorSetManager.updateInputAttachment({}, subpassInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1523,7 +1484,7 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
|||||||
swapChain->acquire(resized);
|
swapChain->acquire(resized);
|
||||||
|
|
||||||
if (resized) {
|
if (resized) {
|
||||||
mFramebufferCache.resetFramebuffers();
|
mFramebufferCache.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UTILS_LIKELY(mDefaultRenderTarget)) {
|
if (UTILS_LIKELY(mDefaultRenderTarget)) {
|
||||||
@@ -1832,9 +1793,9 @@ void VulkanDriver::bindDescriptorSet(
|
|||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
if (dsh) {
|
if (dsh) {
|
||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
mDescriptorSetCache.bind(setIndex, set, std::move(offsets));
|
mDescriptorSetManager.bind(setIndex, set, std::move(offsets));
|
||||||
} else {
|
} else {
|
||||||
mDescriptorSetCache.unbind(setIndex);
|
mDescriptorSetManager.unbind(setIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1842,7 +1803,7 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
||||||
|
|
||||||
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
|
mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer,
|
||||||
mBoundPipeline.pipelineLayout,
|
mBoundPipeline.pipelineLayout,
|
||||||
mBoundPipeline.descriptorSetMask);
|
mBoundPipeline.descriptorSetMask);
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,8 @@
|
|||||||
#include "VulkanSamplerCache.h"
|
#include "VulkanSamplerCache.h"
|
||||||
#include "VulkanStagePool.h"
|
#include "VulkanStagePool.h"
|
||||||
#include "VulkanQueryManager.h"
|
#include "VulkanQueryManager.h"
|
||||||
#include "VulkanYcbcrConversionCache.h"
|
#include "vulkan/caching/VulkanDescriptorSetManager.h"
|
||||||
#include "vulkan/VulkanDescriptorSetCache.h"
|
#include "vulkan/caching/VulkanPipelineLayoutCache.h"
|
||||||
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
|
|
||||||
#include "vulkan/VulkanPipelineLayoutCache.h"
|
|
||||||
#include "vulkan/memory/ResourceManager.h"
|
#include "vulkan/memory/ResourceManager.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Definitions.h"
|
#include "vulkan/utils/Definitions.h"
|
||||||
@@ -136,12 +134,10 @@ private:
|
|||||||
VulkanPipelineCache mPipelineCache;
|
VulkanPipelineCache mPipelineCache;
|
||||||
VulkanStagePool mStagePool;
|
VulkanStagePool mStagePool;
|
||||||
VulkanFboCache mFramebufferCache;
|
VulkanFboCache mFramebufferCache;
|
||||||
VulkanYcbcrConversionCache mYcbcrConversionCache;
|
|
||||||
VulkanSamplerCache mSamplerCache;
|
VulkanSamplerCache mSamplerCache;
|
||||||
VulkanBlitter mBlitter;
|
VulkanBlitter mBlitter;
|
||||||
VulkanReadPixels mReadPixels;
|
VulkanReadPixels mReadPixels;
|
||||||
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
VulkanDescriptorSetManager mDescriptorSetManager;
|
||||||
VulkanDescriptorSetCache mDescriptorSetCache;
|
|
||||||
VulkanQueryManager mQueryManager;
|
VulkanQueryManager mQueryManager;
|
||||||
|
|
||||||
// This is necessary for us to write to push constants after binding a pipeline.
|
// This is necessary for us to write to push constants after binding a pipeline.
|
||||||
|
|||||||
@@ -340,21 +340,15 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept
|
|||||||
return renderPass;
|
return renderPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanFboCache::resetFramebuffers() noexcept {
|
void VulkanFboCache::reset() noexcept {
|
||||||
for (const auto& pair: mFramebufferCache) {
|
for (auto pair : mFramebufferCache) {
|
||||||
mRenderPassRefCount[pair.first.renderPass]--;
|
mRenderPassRefCount[pair.first.renderPass]--;
|
||||||
vkDestroyFramebuffer(mDevice, pair.second.handle, VKALLOC);
|
vkDestroyFramebuffer(mDevice, pair.second.handle, VKALLOC);
|
||||||
}
|
}
|
||||||
mFramebufferCache.clear();
|
mFramebufferCache.clear();
|
||||||
}
|
for (auto pair : mRenderPassCache) {
|
||||||
|
|
||||||
void VulkanFboCache::terminate() noexcept {
|
|
||||||
resetFramebuffers();
|
|
||||||
|
|
||||||
for (const auto& pair: mRenderPassCache) {
|
|
||||||
vkDestroyRenderPass(mDevice, pair.second.handle, VKALLOC);
|
vkDestroyRenderPass(mDevice, pair.second.handle, VKALLOC);
|
||||||
}
|
}
|
||||||
mRenderPassRefCount.clear();
|
|
||||||
mRenderPassCache.clear();
|
mRenderPassCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,11 +106,8 @@ public:
|
|||||||
// Evicts old unused Vulkan objects. Call this once per frame.
|
// Evicts old unused Vulkan objects. Call this once per frame.
|
||||||
void gc() noexcept;
|
void gc() noexcept;
|
||||||
|
|
||||||
// Frees all Framebuffer objects. Call this every time a the swapchain is resized
|
|
||||||
void resetFramebuffers() noexcept;
|
|
||||||
|
|
||||||
// Frees all Vulkan objects. Call this during shutdown before the device is destroyed.
|
// Frees all Vulkan objects. Call this during shutdown before the device is destroyed.
|
||||||
void terminate() noexcept;
|
void reset() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <utils/compiler.h> // UTILS_FALLTHROUGH
|
|
||||||
#include <utils/Panic.h> // ASSERT_POSTCONDITION
|
#include <utils/Panic.h> // ASSERT_POSTCONDITION
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
@@ -90,9 +89,8 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO: properly handle external sampler
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
case DescriptorType::SAMPLER_EXTERNAL:
|
||||||
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
|
|
||||||
UTILS_FALLTHROUGH;
|
|
||||||
case DescriptorType::SAMPLER: {
|
case DescriptorType::SAMPLER: {
|
||||||
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -66,21 +66,18 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
|
|
||||||
// The bitmask representation of a set layout.
|
// The bitmask representation of a set layout.
|
||||||
struct Bitmask {
|
struct Bitmask {
|
||||||
|
// TODO: better utiltize the space below and use bitset instead.
|
||||||
fvkutils::UniformBufferBitmask ubo; // 8 bytes
|
fvkutils::UniformBufferBitmask ubo; // 8 bytes
|
||||||
fvkutils::UniformBufferBitmask dynamicUbo; // 8 bytes
|
fvkutils::UniformBufferBitmask dynamicUbo; // 8 bytes
|
||||||
fvkutils::SamplerBitmask sampler; // 8 bytes
|
fvkutils::SamplerBitmask sampler; // 8 bytes
|
||||||
fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes
|
fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes
|
||||||
|
|
||||||
// This is a subset of the bitmask.sampler field.
|
|
||||||
fvkutils::SamplerBitmask externalSampler; // 8 bytes
|
|
||||||
|
|
||||||
bool operator==(Bitmask const& right) const {
|
bool operator==(Bitmask const& right) const {
|
||||||
return ubo == right.ubo && dynamicUbo == right.dynamicUbo && sampler == right.sampler &&
|
return ubo == right.ubo && dynamicUbo == right.dynamicUbo && sampler == right.sampler &&
|
||||||
inputAttachment == right.inputAttachment &&
|
inputAttachment == right.inputAttachment;
|
||||||
externalSampler == right.externalSampler;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Bitmask) == 40);
|
static_assert(sizeof(Bitmask) == 32);
|
||||||
|
|
||||||
// This is a convenience struct to quickly check layout compatibility in terms of descriptor set
|
// This is a convenience struct to quickly check layout compatibility in terms of descriptor set
|
||||||
// pools.
|
// pools.
|
||||||
@@ -122,16 +119,10 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
|
|
||||||
VulkanDescriptorSetLayout(DescriptorSetLayout const& layout);
|
VulkanDescriptorSetLayout(DescriptorSetLayout const& layout);
|
||||||
|
|
||||||
// Note that we don't destroy the vklayout. This is done by the layout cache.
|
|
||||||
~VulkanDescriptorSetLayout() = default;
|
~VulkanDescriptorSetLayout() = default;
|
||||||
|
|
||||||
VkDescriptorSetLayout const& getVkLayout() const noexcept { return mVkLayout; }
|
VkDescriptorSetLayout getVkLayout() const { return mVkLayout; }
|
||||||
|
void setVkLayout(VkDescriptorSetLayout vklayout) { mVkLayout = vklayout; }
|
||||||
// It is possible to have the layout switch out due to AHardwarebuffer (external image) format
|
|
||||||
// changes.
|
|
||||||
void setVkLayout(VkDescriptorSetLayout vklayout) noexcept { mVkLayout = vklayout; }
|
|
||||||
|
|
||||||
bool hasExternalSamplers() const noexcept { return bitmask.externalSampler.count() > 0; }
|
|
||||||
|
|
||||||
Bitmask const bitmask;
|
Bitmask const bitmask;
|
||||||
Count const count;
|
Count const count;
|
||||||
@@ -146,11 +137,12 @@ public:
|
|||||||
// can use to repackage the vk handle.
|
// can use to repackage the vk handle.
|
||||||
using OnRecycle = std::function<void(VulkanDescriptorSet*)>;
|
using OnRecycle = std::function<void(VulkanDescriptorSet*)>;
|
||||||
|
|
||||||
VulkanDescriptorSet(
|
VulkanDescriptorSet(VkDescriptorSet rawSet,
|
||||||
fvkutils::UniformBufferBitmask const& dynamicUboMask,
|
fvkutils::UniformBufferBitmask const& dynamicUboMask,
|
||||||
uint8_t uniqueDynamicUboCount,
|
uint8_t uniqueDynamicUboCount,
|
||||||
OnRecycle&& onRecycleFn)
|
OnRecycle&& onRecycleFn)
|
||||||
: dynamicUboMask(dynamicUboMask),
|
: vkSet(rawSet),
|
||||||
|
dynamicUboMask(dynamicUboMask),
|
||||||
uniqueDynamicUboCount(uniqueDynamicUboCount),
|
uniqueDynamicUboCount(uniqueDynamicUboCount),
|
||||||
mOnRecycleFn(std::move(onRecycleFn)) {}
|
mOnRecycleFn(std::move(onRecycleFn)) {}
|
||||||
|
|
||||||
@@ -160,13 +152,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet const& getVkSet() const noexcept {
|
|
||||||
return mVkSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that the only case where you'd set it more than once is with external images/samplers.
|
|
||||||
void setVkSet(VkDescriptorSet vkset) noexcept { mVkSet = vkset; }
|
|
||||||
|
|
||||||
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
|
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
|
||||||
mOffsets = std::move(offsets);
|
mOffsets = std::move(offsets);
|
||||||
}
|
}
|
||||||
@@ -178,11 +163,11 @@ public:
|
|||||||
void acquire(fvkmemory::resource_ptr<VulkanTexture> texture);
|
void acquire(fvkmemory::resource_ptr<VulkanTexture> texture);
|
||||||
void acquire(fvkmemory::resource_ptr<VulkanBufferObject> buffer);
|
void acquire(fvkmemory::resource_ptr<VulkanBufferObject> buffer);
|
||||||
|
|
||||||
|
VkDescriptorSet const vkSet;
|
||||||
fvkutils::UniformBufferBitmask const dynamicUboMask;
|
fvkutils::UniformBufferBitmask const dynamicUboMask;
|
||||||
uint8_t const uniqueDynamicUboCount;
|
uint8_t const uniqueDynamicUboCount;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDescriptorSet mVkSet = VK_NULL_HANDLE;
|
|
||||||
backend::DescriptorSetOffsetArray mOffsets;
|
backend::DescriptorSetOffsetArray mOffsets;
|
||||||
std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources;
|
std::vector<fvkmemory::resource_ptr<fvkmemory::Resource>> mResources;
|
||||||
OnRecycle mOnRecycleFn;
|
OnRecycle mOnRecycleFn;
|
||||||
|
|||||||
@@ -15,12 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanPipelineCache.h"
|
#include "VulkanPipelineCache.h"
|
||||||
|
#include "VulkanMemory.h"
|
||||||
|
#include "caching/VulkanDescriptorSetManager.h"
|
||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
#include "VulkanConstants.h"
|
#include "VulkanConstants.h"
|
||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
@@ -35,12 +38,7 @@ using namespace bluevk;
|
|||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
VulkanPipelineCache::VulkanPipelineCache(VkDevice device)
|
VulkanPipelineCache::VulkanPipelineCache(VkDevice device)
|
||||||
: mDevice(device) {
|
: mDevice(device) {}
|
||||||
VkPipelineCacheCreateInfo createInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
|
|
||||||
};
|
|
||||||
bluevk::vkCreatePipelineCache(mDevice, &createInfo, VKALLOC, &mPipelineCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
|
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
|
||||||
mPipelineRequirements.layout = layout;
|
mPipelineRequirements.layout = layout;
|
||||||
@@ -220,7 +218,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
PipelineCacheEntry cacheEntry = {
|
PipelineCacheEntry cacheEntry = {
|
||||||
.lastUsed = mCurrentTime,
|
.lastUsed = mCurrentTime,
|
||||||
};
|
};
|
||||||
VkResult error = vkCreateGraphicsPipelines(mDevice, mPipelineCache, 1, &pipelineCreateInfo,
|
VkResult error = vkCreateGraphicsPipelines(mDevice, VK_NULL_HANDLE, 1, &pipelineCreateInfo,
|
||||||
VKALLOC, &cacheEntry.handle);
|
VKALLOC, &cacheEntry.handle);
|
||||||
assert_invariant(error == VK_SUCCESS);
|
assert_invariant(error == VK_SUCCESS);
|
||||||
if (error != VK_SUCCESS) {
|
if (error != VK_SUCCESS) {
|
||||||
@@ -276,8 +274,6 @@ void VulkanPipelineCache::terminate() noexcept {
|
|||||||
}
|
}
|
||||||
mPipelines.clear();
|
mPipelines.clear();
|
||||||
mBoundPipeline = {};
|
mBoundPipeline = {};
|
||||||
|
|
||||||
vkDestroyPipelineCache(mDevice, mPipelineCache, VKALLOC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::gc() noexcept {
|
void VulkanPipelineCache::gc() noexcept {
|
||||||
|
|||||||
@@ -18,18 +18,24 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H
|
||||||
|
|
||||||
#include "VulkanCommands.h"
|
#include "VulkanCommands.h"
|
||||||
|
#include "VulkanMemory.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include "backend/Program.h"
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
#include <utils/bitset.h>
|
#include <utils/bitset.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -198,10 +204,6 @@ private:
|
|||||||
// Immutable state.
|
// Immutable state.
|
||||||
VkDevice mDevice = VK_NULL_HANDLE;
|
VkDevice mDevice = VK_NULL_HANDLE;
|
||||||
|
|
||||||
// Vuklan Driver pipeline cache handle. In the cases a pipeline has been evicted by the `gc`,
|
|
||||||
// recreating the same pipeline is cheaper, helping with frame stalling.
|
|
||||||
VkPipelineCache mPipelineCache = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
// Current requirements for the pipeline layout, pipeline, and descriptor sets.
|
// Current requirements for the pipeline layout, pipeline, and descriptor sets.
|
||||||
PipelineKey mPipelineRequirements = {};
|
PipelineKey mPipelineRequirements = {};
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanSamplerCache.h"
|
#include "vulkan/VulkanSamplerCache.h"
|
||||||
|
|
||||||
#include "VulkanConstants.h"
|
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
@@ -25,51 +23,117 @@ using namespace bluevk;
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
constexpr inline VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) noexcept {
|
||||||
|
switch (mode) {
|
||||||
|
case SamplerWrapMode::REPEAT:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
case SamplerWrapMode::CLAMP_TO_EDGE:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
case SamplerWrapMode::MIRRORED_REPEAT:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkFilter getFilter(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkFilter getFilter(SamplerMagFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMagFilter::NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMagFilter::LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline float getMaxLod(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
||||||
|
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
||||||
|
return 0.25f;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_LOD_CLAMP_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept {
|
||||||
|
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
||||||
: mDevice(device) {}
|
: mDevice(device) {}
|
||||||
|
|
||||||
VkSampler VulkanSamplerCache::getSampler(Params params) noexcept {
|
VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept {
|
||||||
auto iter = mCache.find(params);
|
auto iter = mCache.find(params);
|
||||||
if (UTILS_LIKELY(iter != mCache.end())) {
|
if (UTILS_LIKELY(iter != mCache.end())) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
VkSamplerYcbcrConversionInfo ycbcrConversion = {
|
VkSamplerCreateInfo samplerInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.conversion = params.conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const& samplerParams = params.sampler;
|
|
||||||
VkSamplerCreateInfo samplerInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
.pNext = params.conversion != VK_NULL_HANDLE ? &ycbcrConversion : VK_NULL_HANDLE,
|
.magFilter = getFilter(params.filterMag),
|
||||||
.magFilter = fvkutils::getFilter(samplerParams.filterMag),
|
.minFilter = getFilter(params.filterMin),
|
||||||
.minFilter = fvkutils::getFilter(samplerParams.filterMin),
|
.mipmapMode = getMipmapMode(params.filterMin),
|
||||||
.mipmapMode = fvkutils::getMipmapMode(samplerParams.filterMin),
|
.addressModeU = getWrapMode(params.wrapS),
|
||||||
.addressModeU = fvkutils::getWrapMode(samplerParams.wrapS),
|
.addressModeV = getWrapMode(params.wrapT),
|
||||||
.addressModeV = fvkutils::getWrapMode(samplerParams.wrapT),
|
.addressModeW = getWrapMode(params.wrapR),
|
||||||
.addressModeW = fvkutils::getWrapMode(samplerParams.wrapR),
|
.anisotropyEnable = params.anisotropyLog2 == 0 ? 0u : 1u,
|
||||||
.anisotropyEnable = samplerParams.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
||||||
.maxAnisotropy = (float) (1u << samplerParams.anisotropyLog2),
|
.compareEnable = getCompareEnable(params.compareMode),
|
||||||
.compareEnable = fvkutils::getCompareEnable(samplerParams.compareMode),
|
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
||||||
.compareOp = fvkutils::getCompareOp(samplerParams.compareFunc),
|
|
||||||
.minLod = 0.0f,
|
.minLod = 0.0f,
|
||||||
.maxLod = fvkutils::getMaxLod(samplerParams.filterMin),
|
.maxLod = getMaxLod(params.filterMin),
|
||||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||||
.unnormalizedCoordinates = VK_FALSE,
|
.unnormalizedCoordinates = VK_FALSE
|
||||||
};
|
};
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
VkResult result = vkCreateSampler(mDevice, &samplerInfo, VKALLOC, &sampler);
|
VkResult result = vkCreateSampler(mDevice, &samplerInfo, VKALLOC, &sampler);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create sampler."
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create sampler."
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
mCache.insert({ params, sampler });
|
mCache.insert({params, sampler});
|
||||||
return sampler;
|
return sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSamplerCache::terminate() noexcept {
|
void VulkanSamplerCache::terminate() noexcept {
|
||||||
for (auto pair: mCache) {
|
for (auto pair : mCache) {
|
||||||
vkDestroySampler(mDevice, pair.second, VKALLOC);
|
vkDestroySampler(mDevice, pair.second, VKALLOC);
|
||||||
}
|
}
|
||||||
mCache.clear();
|
mCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -17,11 +17,8 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
#ifndef TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include "VulkanContext.h"
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
@@ -29,28 +26,12 @@ namespace filament::backend {
|
|||||||
// Simple manager for VkSampler objects.
|
// Simple manager for VkSampler objects.
|
||||||
class VulkanSamplerCache {
|
class VulkanSamplerCache {
|
||||||
public:
|
public:
|
||||||
struct Params {
|
|
||||||
SamplerParams sampler = {};
|
|
||||||
uint32_t padding = 0;
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(Params) == 16);
|
|
||||||
|
|
||||||
explicit VulkanSamplerCache(VkDevice device);
|
explicit VulkanSamplerCache(VkDevice device);
|
||||||
VkSampler getSampler(Params params) noexcept;
|
VkSampler getSampler(SamplerParams params) noexcept;
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
|
tsl::robin_map<SamplerParams, VkSampler, SamplerParams::Hasher, SamplerParams::EqualTo> mCache;
|
||||||
struct SamplerEqualTo {
|
|
||||||
bool operator()(Params lhs, Params rhs) const noexcept {
|
|
||||||
SamplerParams::EqualTo equal;
|
|
||||||
return equal(lhs.sampler, rhs.sampler) && lhs.conversion == rhs.conversion;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using SamplerHashFn = utils::hash::MurmurHashFn<Params>;
|
|
||||||
tsl::robin_map<Params, VkSampler, SamplerHashFn, SamplerEqualTo> mCache;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const&
|
|||||||
VulkanCommands* commands, VulkanStagePool& stagePool, void* nativeWindow, uint64_t flags,
|
VulkanCommands* commands, VulkanStagePool& stagePool, void* nativeWindow, uint64_t flags,
|
||||||
VkExtent2D extent)
|
VkExtent2D extent)
|
||||||
: mPlatform(platform),
|
: mPlatform(platform),
|
||||||
mContext(context),
|
|
||||||
mResourceManager(resourceManager),
|
mResourceManager(resourceManager),
|
||||||
mCommands(commands),
|
mCommands(commands),
|
||||||
mAllocator(allocator),
|
mAllocator(allocator),
|
||||||
@@ -78,16 +77,16 @@ void VulkanSwapChain::update() {
|
|||||||
}
|
}
|
||||||
for (auto const color: bundle.colors) {
|
for (auto const color: bundle.colors) {
|
||||||
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
|
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
|
||||||
mContext, device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
|
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
|
||||||
bundle.colorFormat, VK_NULL_HANDLE /*ycrcb */, 1, bundle.extent.width,
|
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, colorUsage,
|
||||||
bundle.extent.height, bundle.layerCount, colorUsage, mStagePool);
|
mStagePool);
|
||||||
mColors.push_back(colorTexture);
|
mColors.push_back(colorTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, mContext, device,
|
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
|
||||||
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
|
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
|
||||||
bundle.depthFormat, VK_NULL_HANDLE /*ycrcb */, 1, bundle.extent.width,
|
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, depthUsage,
|
||||||
bundle.extent.height, bundle.layerCount, depthUsage, mStagePool);
|
mStagePool);
|
||||||
|
|
||||||
mExtent = bundle.extent;
|
mExtent = bundle.extent;
|
||||||
mLayerCount = bundle.layerCount;
|
mLayerCount = bundle.layerCount;
|
||||||
@@ -108,6 +107,11 @@ void VulkanSwapChain::present() {
|
|||||||
|
|
||||||
mCommands->flush();
|
mCommands->flush();
|
||||||
|
|
||||||
|
// call the image ready wait function
|
||||||
|
if (mExplicitImageReadyWait != nullptr) {
|
||||||
|
mExplicitImageReadyWait(swapChain);
|
||||||
|
}
|
||||||
|
|
||||||
// We only present if it is not headless. No-op for headless.
|
// We only present if it is not headless. No-op for headless.
|
||||||
if (!mHeadless) {
|
if (!mHeadless) {
|
||||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||||
@@ -141,6 +145,7 @@ void VulkanSwapChain::acquire(bool& resized) {
|
|||||||
VulkanPlatform::ImageSyncData imageSyncData;
|
VulkanPlatform::ImageSyncData imageSyncData;
|
||||||
VkResult const result = mPlatform->acquire(swapChain, &imageSyncData);
|
VkResult const result = mPlatform->acquire(swapChain, &imageSyncData);
|
||||||
mCurrentSwapIndex = imageSyncData.imageIndex;
|
mCurrentSwapIndex = imageSyncData.imageIndex;
|
||||||
|
mExplicitImageReadyWait = imageSyncData.explicitImageReadyWait;
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||||
<< "Cannot acquire in swapchain. error=" << static_cast<int32_t>(result);
|
<< "Cannot acquire in swapchain. error=" << static_cast<int32_t>(result);
|
||||||
if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) {
|
if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "DriverBase.h"
|
#include "DriverBase.h"
|
||||||
|
|
||||||
#include "VulkanConstants.h"
|
|
||||||
#include "VulkanContext.h"
|
#include "VulkanContext.h"
|
||||||
#include "VulkanTexture.h"
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/memory/Resource.h"
|
#include "vulkan/memory/Resource.h"
|
||||||
@@ -29,6 +28,7 @@
|
|||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
@@ -49,9 +49,7 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
|
|||||||
|
|
||||||
void present();
|
void present();
|
||||||
|
|
||||||
// Acquire a new image from the swapchain. If the image is not available it would wait until it
|
void acquire(bool& reized);
|
||||||
// is.
|
|
||||||
void acquire(bool& resized);
|
|
||||||
|
|
||||||
fvkmemory::resource_ptr<VulkanTexture> getCurrentColor() const noexcept {
|
fvkmemory::resource_ptr<VulkanTexture> getCurrentColor() const noexcept {
|
||||||
uint32_t const imageIndex = mCurrentSwapIndex;
|
uint32_t const imageIndex = mCurrentSwapIndex;
|
||||||
@@ -85,7 +83,6 @@ private:
|
|||||||
void update();
|
void update();
|
||||||
|
|
||||||
VulkanPlatform* mPlatform;
|
VulkanPlatform* mPlatform;
|
||||||
VulkanContext const& mContext;
|
|
||||||
fvkmemory::ResourceManager* mResourceManager;
|
fvkmemory::ResourceManager* mResourceManager;
|
||||||
VulkanCommands* mCommands;
|
VulkanCommands* mCommands;
|
||||||
VmaAllocator mAllocator;
|
VmaAllocator mAllocator;
|
||||||
@@ -101,6 +98,7 @@ private:
|
|||||||
VkExtent2D mExtent;
|
VkExtent2D mExtent;
|
||||||
uint32_t mLayerCount;
|
uint32_t mLayerCount;
|
||||||
uint32_t mCurrentSwapIndex;
|
uint32_t mCurrentSwapIndex;
|
||||||
|
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
|
||||||
bool mAcquired;
|
bool mAcquired;
|
||||||
bool mIsFirstRenderPass;
|
bool mIsFirstRenderPass;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanCommands.h"
|
#include "VulkanCommands.h"
|
||||||
#include "VulkanContext.h"
|
|
||||||
#include "VulkanMemory.h"
|
#include "VulkanMemory.h"
|
||||||
#include "VulkanTexture.h"
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
@@ -55,10 +54,13 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
|
|||||||
VK_COMPONENT_SWIZZLE_B,
|
VK_COMPONENT_SWIZZLE_B,
|
||||||
VK_COMPONENT_SWIZZLE_A,
|
VK_COMPONENT_SWIZZLE_A,
|
||||||
};
|
};
|
||||||
auto const compose = [](VkComponentMapping const& prev,
|
|
||||||
VkComponentMapping const& next) -> VkComponentMapping {
|
auto const compose = [](VkComponentSwizzle out, VkComponentMapping const& prev,
|
||||||
VkComponentSwizzle vals[4] = { next.r, next.g, next.b, next.a };
|
uint8_t channelIndex) {
|
||||||
for (auto& out: vals) {
|
// We need to first change all identities to its equivalent channel.
|
||||||
|
if (out == VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||||
|
out = IDENTITY[channelIndex];
|
||||||
|
}
|
||||||
switch (out) {
|
switch (out) {
|
||||||
case VK_COMPONENT_SWIZZLE_R:
|
case VK_COMPONENT_SWIZZLE_R:
|
||||||
out = prev.r;
|
out = prev.r;
|
||||||
@@ -72,44 +74,44 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
|
|||||||
case VK_COMPONENT_SWIZZLE_A:
|
case VK_COMPONENT_SWIZZLE_A:
|
||||||
out = prev.a;
|
out = prev.a;
|
||||||
break;
|
break;
|
||||||
// Do not modify the value
|
|
||||||
case VK_COMPONENT_SWIZZLE_IDENTITY:
|
case VK_COMPONENT_SWIZZLE_IDENTITY:
|
||||||
case VK_COMPONENT_SWIZZLE_ZERO:
|
case VK_COMPONENT_SWIZZLE_ZERO:
|
||||||
case VK_COMPONENT_SWIZZLE_ONE:
|
case VK_COMPONENT_SWIZZLE_ONE:
|
||||||
|
return out;
|
||||||
// Below is not exposed in Vulkan's API, but needs to be there for compilation.
|
// Below is not exposed in Vulkan's API, but needs to be there for compilation.
|
||||||
case VK_COMPONENT_SWIZZLE_MAX_ENUM:
|
case VK_COMPONENT_SWIZZLE_MAX_ENUM:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// If the result correctly corresponds to the identity, just return identity.
|
||||||
|
if (IDENTITY[channelIndex] == out) {
|
||||||
|
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
}
|
}
|
||||||
return { vals[0], vals[1], vals[2], vals[3] };
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const identityToChannel = [](VkComponentMapping const& mapping) -> VkComponentMapping {
|
auto const identityToChannel = [](VkComponentSwizzle val, uint8_t channelIndex) {
|
||||||
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
|
if (val != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
return val;
|
||||||
if (vals[i] != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
vals[i] = IDENTITY[i];
|
return IDENTITY[channelIndex];
|
||||||
}
|
|
||||||
return { vals[0], vals[1], vals[2], vals[3] };
|
|
||||||
};
|
|
||||||
auto const channelToIdentity = [](VkComponentMapping const& mapping) -> VkComponentMapping {
|
|
||||||
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
|
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
|
||||||
if (IDENTITY[i] != vals[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vals[i] = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
}
|
|
||||||
return { vals[0], vals[1], vals[2], vals[3] };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We make sure all all identities are mapped into respective channels so that actual channel
|
// We make sure all all identities are mapped into respective channels so that actual channel
|
||||||
// mapping will be passed onto the output.
|
// mapping will be passed onto the output.
|
||||||
VkComponentMapping const prevExplicit = identityToChannel(prev);
|
VkComponentMapping const prevExplicit = {
|
||||||
VkComponentMapping const nextExplicit = identityToChannel(next);
|
identityToChannel(prev.r, 0),
|
||||||
return channelToIdentity(compose(prevExplicit, nextExplicit));
|
identityToChannel(prev.g, 1),
|
||||||
|
identityToChannel(prev.b, 2),
|
||||||
|
identityToChannel(prev.a, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note that the channel index corresponds to the VkComponentMapping struct layout.
|
||||||
|
return {
|
||||||
|
compose(next.r, prevExplicit, 0),
|
||||||
|
compose(next.g, prevExplicit, 1),
|
||||||
|
compose(next.b, prevExplicit, 2),
|
||||||
|
compose(next.a, prevExplicit, 3),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
||||||
@@ -151,152 +153,36 @@ uint8_t getLayerCountFromDepth(uint32_t const depth) {
|
|||||||
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
|
|
||||||
VkPhysicalDevice physicalDevice, VkFormat vkFormat, TextureUsage tusage) {
|
|
||||||
VkImageUsageFlags usage = {};
|
|
||||||
if (any(tusage & TextureUsage::BLIT_SRC)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
}
|
|
||||||
if (any(tusage & TextureUsage::BLIT_DST)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if we can use the transient usage flag combined with lazily allocated memory.
|
|
||||||
const bool useTransientAttachment =
|
|
||||||
// Lazily allocated memory is available.
|
|
||||||
context.isLazilyAllocatedMemorySupported() &&
|
|
||||||
// Usage consists of attachment flags only.
|
|
||||||
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
|
||||||
// Usage contains at least one attachment flag.
|
|
||||||
any(tusage & TextureUsage::ALL_ATTACHMENTS) &&
|
|
||||||
// Depth resolve cannot use transient attachment because it uses a custom shader.
|
|
||||||
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
|
|
||||||
// restriction.
|
|
||||||
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
|
|
||||||
// and above to be able to support stencil resolve (along with depth).
|
|
||||||
!(any(tusage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
|
|
||||||
|
|
||||||
const VkImageUsageFlags transientFlag =
|
|
||||||
useTransientAttachment ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0U;
|
|
||||||
|
|
||||||
if (any(tusage & TextureUsage::SAMPLEABLE)) {
|
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
|
||||||
if (physicalDevice != VK_NULL_HANDLE) {
|
|
||||||
// Validate that the format is actually sampleable.
|
|
||||||
VkFormatProperties props;
|
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &props);
|
|
||||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
|
||||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
|
|
||||||
"sampleable with optimal tiling." << utils::io::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
}
|
|
||||||
if (any(tusage & TextureUsage::COLOR_ATTACHMENT)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | transientFlag;
|
|
||||||
if (any(tusage & TextureUsage::SUBPASS_INPUT)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (any(tusage & TextureUsage::STENCIL_ATTACHMENT)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;
|
|
||||||
}
|
|
||||||
if (any(tusage & TextureUsage::UPLOADABLE)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
if (any(tusage & TextureUsage::DEPTH_ATTACHMENT)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;
|
|
||||||
|
|
||||||
// Depth resolves uses a custom shader and therefore needs to be sampleable.
|
|
||||||
if (samples > 1) {
|
|
||||||
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands,
|
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
||||||
VmaAllocator allocator, VkDevice device, VkImage image, VkDeviceMemory deviceMemory,
|
VulkanCommands* commands, VulkanStagePool& stagePool, VkFormat format,
|
||||||
VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
VkImageViewType viewType, uint8_t levels, uint8_t layerCount, VulkanLayout defaultLayout,
|
||||||
VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat, VkImageUsageFlags usage,
|
|
||||||
bool isProtected)
|
bool isProtected)
|
||||||
: mStagePool(stagePool),
|
: mVkFormat(format),
|
||||||
mCommands(commands),
|
|
||||||
mAllocator(allocator),
|
|
||||||
mDevice(device),
|
|
||||||
mTextureImage(image),
|
|
||||||
mTextureImageMemory(deviceMemory),
|
|
||||||
mVkFormat(format),
|
|
||||||
mViewType(viewType),
|
mViewType(viewType),
|
||||||
mFullViewRange{ fvkutils::getImageAspect(format), 0, levels, 0, layerCount },
|
mFullViewRange{fvkutils::getImageAspect(format), 0, levels, 0, layerCount},
|
||||||
mYcbcr{ ycbcrConversion, isExternalFormat },
|
mDefaultLayout(defaultLayout),
|
||||||
mDefaultLayout(getDefaultLayoutImpl(usage)),
|
mIsProtected(isProtected),
|
||||||
mUsage(usage),
|
mStagePool(stagePool),
|
||||||
mIsProtected(isProtected) {}
|
mDevice(device),
|
||||||
|
mAllocator(allocator),
|
||||||
|
mCommands(commands),
|
||||||
|
mIsTransientAttachment(false) {}
|
||||||
|
|
||||||
VulkanTextureState::~VulkanTextureState() {
|
// Constructor for internally passed VkImage
|
||||||
if (mTextureImageMemory != VK_NULL_HANDLE) {
|
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||||
vkDestroyImage(mDevice, mTextureImage, VKALLOC);
|
|
||||||
vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC);
|
|
||||||
}
|
|
||||||
clearCachedImageViews();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanTextureState::clearCachedImageViews() noexcept {
|
|
||||||
for (auto entry: mCachedImageViews) {
|
|
||||||
vkDestroyImageView(mDevice, entry.second, VKALLOC);
|
|
||||||
}
|
|
||||||
mCachedImageViews.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanTextureState::getImageView(VkImageSubresourceRange range, VkImageViewType viewType,
|
|
||||||
VkComponentMapping swizzle) {
|
|
||||||
ImageViewKey const key{ range, viewType, swizzle };
|
|
||||||
if (auto iter = mCachedImageViews.find(key); iter != mCachedImageViews.end()) {
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversionInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.conversion = mYcbcr.conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.pNext = mYcbcr.conversion != VK_NULL_HANDLE ? &conversionInfo : nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.image = mTextureImage,
|
|
||||||
.viewType = viewType,
|
|
||||||
.format = mYcbcr.isExternalFormat ? VK_FORMAT_UNDEFINED : mVkFormat,
|
|
||||||
.components = swizzle,
|
|
||||||
.subresourceRange = range,
|
|
||||||
};
|
|
||||||
VkImageView imageView;
|
|
||||||
vkCreateImageView(mDevice, &viewInfo, VKALLOC, &imageView);
|
|
||||||
mCachedImageViews.emplace(key, imageView);
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructor for internally passed VkImage - including swapchain images and external images.
|
|
||||||
VulkanTexture::VulkanTexture(VulkanContext const& context, VkDevice device, VmaAllocator allocator,
|
|
||||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||||
VkDeviceMemory memory, VkFormat format, VkSamplerYcbcrConversion conversion,
|
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
|
||||||
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage tusage,
|
uint32_t height, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
||||||
VulkanStagePool& stagePool)
|
: HwTexture(getSamplerTypeFromDepth(depth), 1, samples, width, height, depth, TextureFormat::UNUSED,
|
||||||
: HwTexture(getSamplerTypeFromDepth(depth), 1, samples, width, height, depth,
|
tusage),
|
||||||
TextureFormat::UNUSED, tusage),
|
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
||||||
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool,
|
allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
||||||
commands, allocator, device, image, memory, format,
|
/*mipLevels=*/1, getLayerCountFromDepth(depth), getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
|
||||||
fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
mState->mTextureImage = image;
|
||||||
/*mipLevels=*/1, getLayerCountFromDepth(depth), conversion,
|
mState->mTextureImageMemory = memory;
|
||||||
/*isExternalFormat=*/false,
|
|
||||||
getUsage(context, samples, VK_NULL_HANDLE, format, tusage),
|
|
||||||
any(usage & TextureUsage::PROTECTED))) {
|
|
||||||
mPrimaryViewRange = mState->mFullViewRange;
|
mPrimaryViewRange = mState->mFullViewRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,19 +192,21 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, SamplerType target,
|
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, SamplerType target,
|
||||||
uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h,
|
uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h,
|
||||||
uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
||||||
: HwTexture(target, levels, samples, w, h, depth, tformat, tusage) {
|
: HwTexture(target, levels, samples, w, h, depth, tformat, tusage),
|
||||||
|
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
||||||
|
allocator, commands, stagePool, fvkutils::getVkFormat(tformat),
|
||||||
|
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
||||||
|
VulkanLayout::UNDEFINED, any(usage & TextureUsage::PROTECTED))) {
|
||||||
// Create an appropriately-sized device-only VkImage, but do not fill it yet.
|
// Create an appropriately-sized device-only VkImage, but do not fill it yet.
|
||||||
VkFormat const vkFormat = fvkutils::getVkFormat(tformat);
|
|
||||||
bool const isProtected = any(tusage & TextureUsage::PROTECTED);
|
|
||||||
VkImageCreateInfo imageInfo{
|
VkImageCreateInfo imageInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
.imageType = target == SamplerType::SAMPLER_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
|
.imageType = target == SamplerType::SAMPLER_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
|
||||||
.format = vkFormat,
|
.format = mState->mVkFormat,
|
||||||
.extent = {w, h, depth},
|
.extent = {w, h, depth},
|
||||||
.mipLevels = levels,
|
.mipLevels = levels,
|
||||||
.arrayLayers = 1,
|
.arrayLayers = 1,
|
||||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.usage = getUsage(context, samples, physicalDevice, vkFormat, tusage),
|
.usage = 0,
|
||||||
};
|
};
|
||||||
if (target == SamplerType::SAMPLER_3D && any(tusage & TextureUsage::ALL_ATTACHMENTS)) {
|
if (target == SamplerType::SAMPLER_3D && any(tusage & TextureUsage::ALL_ATTACHMENTS)) {
|
||||||
if (context.isImageView2DOn3DImageSupported()) {
|
if (context.isImageView2DOn3DImageSupported()) {
|
||||||
@@ -348,17 +236,72 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
imageInfo.arrayLayers = depth * 6;
|
imageInfo.arrayLayers = depth * 6;
|
||||||
imageInfo.extent.depth = 1;
|
imageInfo.extent.depth = 1;
|
||||||
}
|
}
|
||||||
if (isProtected) {
|
if (any(usage & TextureUsage::PROTECTED)) {
|
||||||
imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
|
imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (any(usage & TextureUsage::BLIT_SRC)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
}
|
||||||
|
if (any(usage & TextureUsage::BLIT_DST)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we can use the transient usage flag combined with lazily allocated memory.
|
||||||
|
const bool useTransientAttachment =
|
||||||
|
// Lazily allocated memory is available.
|
||||||
|
context.isLazilyAllocatedMemorySupported() &&
|
||||||
|
// Usage consists of attachment flags only.
|
||||||
|
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
|
// Usage contains at least one attachment flag.
|
||||||
|
any(tusage & TextureUsage::ALL_ATTACHMENTS);
|
||||||
|
mState->mIsTransientAttachment = useTransientAttachment;
|
||||||
|
|
||||||
|
const VkImageUsageFlags transientFlag =
|
||||||
|
useTransientAttachment ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0U;
|
||||||
|
|
||||||
|
if (any(usage & TextureUsage::SAMPLEABLE)) {
|
||||||
|
|
||||||
|
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||||
|
// Validate that the format is actually sampleable.
|
||||||
|
VkFormatProperties props;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, mState->mVkFormat, &props);
|
||||||
|
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||||
|
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
|
||||||
|
"sampleable with optimal tiling." << utils::io::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
}
|
||||||
|
if (any(usage & TextureUsage::COLOR_ATTACHMENT)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | transientFlag;
|
||||||
|
if (any(usage & TextureUsage::SUBPASS_INPUT)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any(usage & TextureUsage::STENCIL_ATTACHMENT)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;
|
||||||
|
}
|
||||||
|
if (any(usage & TextureUsage::UPLOADABLE)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
}
|
||||||
|
if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;
|
||||||
|
|
||||||
|
// Depth resolves uses a custom shader and therefore needs to be sampleable.
|
||||||
|
if (samples > 1) {
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Constrain the sample count according to the sample count masks in VkPhysicalDeviceProperties.
|
// Constrain the sample count according to the sample count masks in VkPhysicalDeviceProperties.
|
||||||
// Note that VulkanRenderTarget holds a single MSAA count, so we play it safe if this is used as
|
// Note that VulkanRenderTarget holds a single MSAA count, so we play it safe if this is used as
|
||||||
// any kind of attachment (color or depth).
|
// any kind of attachment (color or depth).
|
||||||
auto const& limits = context.getPhysicalDeviceLimits();
|
const auto& limits = context.getPhysicalDeviceLimits();
|
||||||
if (imageInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
|
if (imageInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
|
||||||
samples = fvkutils::reduceSampleCount(samples,
|
samples = fvkutils::reduceSampleCount(samples,
|
||||||
fvkutils::isVkDepthFormat(vkFormat)
|
fvkutils::isVkDepthFormat(mState->mVkFormat)
|
||||||
? limits.sampledImageDepthSampleCounts
|
? limits.sampledImageDepthSampleCounts
|
||||||
: limits.sampledImageColorSampleCounts);
|
: limits.sampledImageColorSampleCounts);
|
||||||
}
|
}
|
||||||
@@ -372,36 +315,33 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
this->samples = samples;
|
this->samples = samples;
|
||||||
imageInfo.samples = (VkSampleCountFlagBits) samples;
|
imageInfo.samples = (VkSampleCountFlagBits) samples;
|
||||||
|
|
||||||
VkImage textureImage;
|
VkResult result = vkCreateImage(mState->mDevice, &imageInfo, VKALLOC, &mState->mTextureImage);
|
||||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &textureImage);
|
|
||||||
if (result != VK_SUCCESS || FVK_ENABLED(FVK_DEBUG_TEXTURE)) {
|
if (result != VK_SUCCESS || FVK_ENABLED(FVK_DEBUG_TEXTURE)) {
|
||||||
FVK_LOGD << "vkCreateImage: "
|
FVK_LOGD << "vkCreateImage: "
|
||||||
<< "image = " << textureImage << ", "
|
<< "image = " << mState->mTextureImage << ", "
|
||||||
<< "result = " << result << ", "
|
<< "result = " << result << ", "
|
||||||
<< "handle = " << utils::io::hex << textureImage << utils::io::dec << ", "
|
<< "handle = " << utils::io::hex << mState->mTextureImage << utils::io::dec << ", "
|
||||||
<< "extent = " << w << "x" << h << "x"<< depth << ", "
|
<< "extent = " << w << "x" << h << "x"<< depth << ", "
|
||||||
<< "mipLevels = " << int(levels) << ", "
|
<< "mipLevels = " << int(levels) << ", "
|
||||||
<< "TextureUsage = " << static_cast<int>(tusage) << ", "
|
<< "TextureUsage = " << static_cast<int>(usage) << ", "
|
||||||
<< "usage = " << imageInfo.usage << ", "
|
<< "usage = " << imageInfo.usage << ", "
|
||||||
<< "samples = " << imageInfo.samples << ", "
|
<< "samples = " << imageInfo.samples << ", "
|
||||||
<< "type = " << imageInfo.imageType << ", "
|
<< "type = " << imageInfo.imageType << ", "
|
||||||
<< "flags = " << imageInfo.flags << ", "
|
<< "flags = " << imageInfo.flags << ", "
|
||||||
<< "target = " << static_cast<int>(target) <<", "
|
<< "target = " << static_cast<int>(target) <<", "
|
||||||
<< "format = " << vkFormat << utils::io::endl;
|
<< "format = " << mState->mVkFormat << utils::io::endl;
|
||||||
}
|
}
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create image."
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create image."
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
// Allocate memory for the VkImage and bind it.
|
// Allocate memory for the VkImage and bind it.
|
||||||
VkMemoryRequirements memReqs;
|
VkMemoryRequirements memReqs = {};
|
||||||
vkGetImageMemoryRequirements(device, textureImage, &memReqs);
|
vkGetImageMemoryRequirements(mState->mDevice, mState->mTextureImage, &memReqs);
|
||||||
|
|
||||||
bool const useTransientAttachment = imageInfo.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
const VkFlags requiredMemoryFlags =
|
||||||
|
|
||||||
VkFlags const requiredMemoryFlags =
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||||
(useTransientAttachment ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0U) |
|
(useTransientAttachment ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0U) |
|
||||||
(isProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U);
|
(mState->mIsProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U);
|
||||||
uint32_t memoryTypeIndex
|
uint32_t memoryTypeIndex
|
||||||
= context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags);
|
= context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags);
|
||||||
|
|
||||||
@@ -413,22 +353,21 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
.allocationSize = memReqs.size,
|
.allocationSize = memReqs.size,
|
||||||
.memoryTypeIndex = memoryTypeIndex,
|
.memoryTypeIndex = memoryTypeIndex,
|
||||||
};
|
};
|
||||||
VkDeviceMemory textureImageMemory;
|
result = vkAllocateMemory(mState->mDevice, &allocInfo, nullptr, &mState->mTextureImageMemory);
|
||||||
result = vkAllocateMemory(device, &allocInfo, nullptr, &textureImageMemory);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to allocate image memory."
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to allocate image memory."
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
result = vkBindImageMemory(device, textureImage, textureImageMemory, 0);
|
result = vkBindImageMemory(mState->mDevice, mState->mTextureImage, mState->mTextureImageMemory,
|
||||||
|
0);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to bind image."
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to bind image."
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
mState = fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, stagePool,
|
|
||||||
commands, allocator, device, textureImage, textureImageMemory, vkFormat,
|
|
||||||
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
|
||||||
VK_NULL_HANDLE /* ycbcrConversion */, false /*isExternalFormat*/, imageInfo.usage,
|
|
||||||
isProtected);
|
|
||||||
|
|
||||||
// Spec out the "primary" VkImageView that shaders use to sample from the image.
|
// Spec out the "primary" VkImageView that shaders use to sample from the image.
|
||||||
mPrimaryViewRange = mState->mFullViewRange;
|
mPrimaryViewRange = mState->mFullViewRange;
|
||||||
|
|
||||||
|
// Go ahead and create the primary image view.
|
||||||
|
getImageView(mPrimaryViewRange, mState->mViewType, mSwizzle);
|
||||||
|
|
||||||
|
mState->mDefaultLayout = getDefaultLayoutImpl(imageInfo.usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor for creating a texture view
|
// Constructor for creating a texture view
|
||||||
@@ -437,8 +376,8 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
fvkmemory::resource_ptr<VulkanTexture> src, uint8_t baseLevel,
|
fvkmemory::resource_ptr<VulkanTexture> src, uint8_t baseLevel,
|
||||||
uint8_t levelCount)
|
uint8_t levelCount)
|
||||||
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
||||||
src->format, src->usage),
|
src->format, src->usage) {
|
||||||
mState(src->mState) {
|
mState = src->mState;
|
||||||
mPrimaryViewRange = src->mPrimaryViewRange;
|
mPrimaryViewRange = src->mPrimaryViewRange;
|
||||||
mPrimaryViewRange.baseMipLevel = src->mPrimaryViewRange.baseMipLevel + baseLevel;
|
mPrimaryViewRange.baseMipLevel = src->mPrimaryViewRange.baseMipLevel + baseLevel;
|
||||||
mPrimaryViewRange.levelCount = levelCount;
|
mPrimaryViewRange.levelCount = levelCount;
|
||||||
@@ -449,10 +388,21 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands,
|
VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands,
|
||||||
fvkmemory::resource_ptr<VulkanTexture> src, VkComponentMapping swizzle)
|
fvkmemory::resource_ptr<VulkanTexture> src, VkComponentMapping swizzle)
|
||||||
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
: HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth,
|
||||||
src->format, src->usage),
|
src->format, src->usage) {
|
||||||
mState(src->mState),
|
mState = src->mState;
|
||||||
mPrimaryViewRange(src->mPrimaryViewRange),
|
mPrimaryViewRange = src->mPrimaryViewRange;
|
||||||
mSwizzle(composeSwizzle(src->mSwizzle, swizzle)) {}
|
mSwizzle = composeSwizzle(src->mSwizzle, swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanTextureState::~VulkanTextureState() {
|
||||||
|
if (mTextureImageMemory != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImage(mDevice, mTextureImage, VKALLOC);
|
||||||
|
vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC);
|
||||||
|
}
|
||||||
|
for (auto entry: mCachedImageViews) {
|
||||||
|
vkDestroyImageView(mDevice, entry.second, VKALLOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||||
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel) {
|
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel) {
|
||||||
@@ -559,20 +509,20 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u
|
|||||||
commands.acquire(fvkmemory::resource_ptr<VulkanTexture>::cast(this));
|
commands.acquire(fvkmemory::resource_ptr<VulkanTexture>::cast(this));
|
||||||
|
|
||||||
// TODO: support blit-based format conversion for 3D images and cubemaps.
|
// TODO: support blit-based format conversion for 3D images and cubemaps.
|
||||||
constexpr int layer = 0;
|
const int layer = 0;
|
||||||
|
|
||||||
VkOffset3D const rect[2] { {0, 0, 0}, {int32_t(width), int32_t(height), 1} };
|
const VkOffset3D rect[2] { {0, 0, 0}, {int32_t(width), int32_t(height), 1} };
|
||||||
|
|
||||||
VkImageAspectFlags const aspect = getImageAspect();
|
const VkImageAspectFlags aspect = getImageAspect();
|
||||||
|
|
||||||
VkImageBlit const blitRegions[1] = {{
|
const VkImageBlit blitRegions[1] = {{
|
||||||
.srcSubresource = { aspect, 0, 0, 1 },
|
.srcSubresource = { aspect, 0, 0, 1 },
|
||||||
.srcOffsets = { rect[0], rect[1] },
|
.srcOffsets = { rect[0], rect[1] },
|
||||||
.dstSubresource = { aspect, uint32_t(miplevel), layer, 1 },
|
.dstSubresource = { aspect, uint32_t(miplevel), layer, 1 },
|
||||||
.dstOffsets = { rect[0], rect[1] }
|
.dstOffsets = { rect[0], rect[1] }
|
||||||
}};
|
}};
|
||||||
|
|
||||||
VkImageSubresourceRange const range = { aspect, miplevel, 1, layer, 1 };
|
const VkImageSubresourceRange range = { aspect, miplevel, 1, layer, 1 };
|
||||||
|
|
||||||
VulkanLayout const newLayout = VulkanLayout::TRANSFER_DST;
|
VulkanLayout const newLayout = VulkanLayout::TRANSFER_DST;
|
||||||
VulkanLayout const oldLayout = getLayout(layer, miplevel);
|
VulkanLayout const oldLayout = getLayout(layer, miplevel);
|
||||||
@@ -588,21 +538,41 @@ VulkanLayout VulkanTexture::getDefaultLayout() const {
|
|||||||
return mState->mDefaultLayout;
|
return mState->mDefaultLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageView VulkanTexture::getAttachmentView(VkImageSubresourceRange const& range, VkImageViewType type) {
|
VkImageView VulkanTexture::getAttachmentView(VkImageSubresourceRange range) {
|
||||||
assert_invariant(mState->mYcbcr.conversion == VK_NULL_HANDLE &&
|
range.levelCount = 1;
|
||||||
"We are not yet supporting external image as attachments.");
|
range.layerCount = 1;
|
||||||
if (type == VK_IMAGE_VIEW_TYPE_2D) {
|
return getImageView(range, VK_IMAGE_VIEW_TYPE_2D, {});
|
||||||
VkImageSubresourceRange copy = range;
|
|
||||||
copy.levelCount = 1;
|
|
||||||
copy.layerCount = 1;
|
|
||||||
return mState->getImageView(copy, type, {});
|
|
||||||
} else {
|
|
||||||
return mState->getImageView(range, type, {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageView VulkanTexture::getView(VkImageSubresourceRange const& range) {
|
VkImageView VulkanTexture::getMultiviewAttachmentView(VkImageSubresourceRange range) {
|
||||||
return mState->getImageView(range, mState->mViewType, mSwizzle);
|
return getImageView(range, VK_IMAGE_VIEW_TYPE_2D_ARRAY, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView VulkanTexture::getViewForType(VkImageSubresourceRange const& range, VkImageViewType type) {
|
||||||
|
return getImageView(range, type, mSwizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range, VkImageViewType viewType,
|
||||||
|
VkComponentMapping swizzle) {
|
||||||
|
VulkanTextureState::ImageViewKey const key{ range, viewType, swizzle };
|
||||||
|
auto iter = mState->mCachedImageViews.find(key);
|
||||||
|
if (iter != mState->mCachedImageViews.end()) {
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
VkImageViewCreateInfo viewInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.image = mState->mTextureImage,
|
||||||
|
.viewType = viewType,
|
||||||
|
.format = mState->mVkFormat,
|
||||||
|
.components = swizzle,
|
||||||
|
.subresourceRange = range,
|
||||||
|
};
|
||||||
|
VkImageView imageView;
|
||||||
|
vkCreateImageView(mState->mDevice, &viewInfo, VKALLOC, &imageView);
|
||||||
|
mState->mCachedImageViews.emplace(key, imageView);
|
||||||
|
return imageView;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageAspectFlags VulkanTexture::getImageAspect() const {
|
VkImageAspectFlags VulkanTexture::getImageAspect() const {
|
||||||
@@ -764,21 +734,6 @@ void VulkanTexture::setLayout(VkImageSubresourceRange const& range, VulkanLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTexture::setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternalFormat) {
|
|
||||||
// Note that this comparison is valid because we only ever create VkSamplerYcbcrConversion from
|
|
||||||
// a cache. So for each set of parameters, there is exactly one conversion (similar to
|
|
||||||
// samplers).
|
|
||||||
VulkanTextureState::Ycbcr ycbcr = {
|
|
||||||
.conversion = conversion,
|
|
||||||
.isExternalFormat = isExternalFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mState->mYcbcr != ycbcr) {
|
|
||||||
mState->mYcbcr = ycbcr;
|
|
||||||
mState->clearCachedImageViews();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanLayout VulkanTexture::getLayout(uint32_t layer, uint32_t level) const {
|
VulkanLayout VulkanTexture::getLayout(uint32_t layer, uint32_t level) const {
|
||||||
assert_invariant(level <= 0xffff && layer <= 0xffff);
|
assert_invariant(level <= 0xffff && layer <= 0xffff);
|
||||||
const uint32_t key = (layer << 16) | level;
|
const uint32_t key = (layer << 16) | level;
|
||||||
|
|||||||
@@ -19,10 +19,7 @@
|
|||||||
|
|
||||||
#include "DriverBase.h"
|
#include "DriverBase.h"
|
||||||
|
|
||||||
#include "VulkanCommands.h"
|
#include "VulkanBuffer.h"
|
||||||
#include "VulkanConstants.h"
|
|
||||||
#include "VulkanMemory.h"
|
|
||||||
#include "VulkanStagePool.h"
|
|
||||||
#include "vulkan/memory/Resource.h"
|
#include "vulkan/memory/Resource.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Image.h"
|
#include "vulkan/utils/Image.h"
|
||||||
@@ -34,14 +31,10 @@
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
struct VulkanTexture;
|
|
||||||
|
|
||||||
struct VulkanTextureState : public fvkmemory::Resource {
|
struct VulkanTextureState : public fvkmemory::Resource {
|
||||||
VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands, VmaAllocator allocator,
|
VulkanTextureState(VkDevice device, VmaAllocator allocator, VulkanCommands* commands,
|
||||||
VkDevice device, VkImage image, VkDeviceMemory deviceMemory, VkFormat format,
|
VulkanStagePool& stagePool, VkFormat format, VkImageViewType viewType, uint8_t levels,
|
||||||
VkImageViewType viewType, uint8_t levels, uint8_t layerCount,
|
uint8_t layerCount, VulkanLayout defaultLayout, bool isProtected);
|
||||||
VkSamplerYcbcrConversion ycbcrConversion, bool isExternalFormat,
|
|
||||||
VkImageUsageFlags usage, bool isProtected);
|
|
||||||
|
|
||||||
~VulkanTextureState();
|
~VulkanTextureState();
|
||||||
|
|
||||||
@@ -64,50 +57,29 @@ struct VulkanTextureState : public fvkmemory::Resource {
|
|||||||
// No implicit padding allowed due to it being a hash key.
|
// No implicit padding allowed due to it being a hash key.
|
||||||
static_assert(sizeof(ImageViewKey) == 40);
|
static_assert(sizeof(ImageViewKey) == 40);
|
||||||
|
|
||||||
VkImageView getImageView(VkImageSubresourceRange range, VkImageViewType viewType,
|
using ImageViewHash = utils::hash::MurmurHashFn<ImageViewKey>;
|
||||||
VkComponentMapping swizzle);
|
|
||||||
private:
|
|
||||||
void clearCachedImageViews() noexcept;
|
|
||||||
VulkanStagePool& mStagePool;
|
|
||||||
VulkanCommands* const mCommands;
|
|
||||||
VmaAllocator const mAllocator;
|
|
||||||
VkDevice const mDevice;
|
|
||||||
|
|
||||||
// The texture with the sidecar owns the sidecar.
|
// The texture with the sidecar owns the sidecar.
|
||||||
fvkmemory::resource_ptr<VulkanTexture> mSidecarMSAA;
|
fvkmemory::resource_ptr<VulkanTexture> mSidecarMSAA;
|
||||||
|
VkDeviceMemory mTextureImageMemory = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkImage const mTextureImage;
|
|
||||||
VkDeviceMemory const mTextureImageMemory;
|
|
||||||
VkFormat const mVkFormat;
|
VkFormat const mVkFormat;
|
||||||
VkImageViewType const mViewType;
|
VkImageViewType const mViewType;
|
||||||
VkImageSubresourceRange const mFullViewRange;
|
VkImageSubresourceRange const mFullViewRange;
|
||||||
|
VkImage mTextureImage = VK_NULL_HANDLE;
|
||||||
|
VulkanLayout mDefaultLayout;
|
||||||
|
|
||||||
// Note that this parameter is not constant due to the fact that AHB can force a change in the
|
bool mIsProtected = false;
|
||||||
// conversion matrix per-frame.
|
|
||||||
struct Ycbcr {
|
|
||||||
VkSamplerYcbcrConversion conversion;
|
|
||||||
bool isExternalFormat;
|
|
||||||
|
|
||||||
bool operator==(Ycbcr const& other) const {
|
|
||||||
return conversion == other.conversion && isExternalFormat == other.isExternalFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(Ycbcr const& other) const {
|
|
||||||
return !((*this) == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
} mYcbcr;
|
|
||||||
|
|
||||||
VulkanLayout const mDefaultLayout;
|
|
||||||
VkImageUsageFlags const mUsage;
|
|
||||||
bool const mIsProtected;
|
|
||||||
|
|
||||||
// Track the image layout of each subresource using a sparse range map.
|
// Track the image layout of each subresource using a sparse range map.
|
||||||
utils::RangeMap<uint32_t, VulkanLayout> mSubresourceLayouts;
|
utils::RangeMap<uint32_t, VulkanLayout> mSubresourceLayouts;
|
||||||
using ImageViewHash = utils::hash::MurmurHashFn<ImageViewKey>;
|
|
||||||
std::unordered_map<ImageViewKey, VkImageView, ImageViewHash> mCachedImageViews;
|
|
||||||
|
|
||||||
friend struct VulkanTexture;
|
std::unordered_map<ImageViewKey, VkImageView, ImageViewHash> mCachedImageViews;
|
||||||
|
VulkanStagePool& mStagePool;
|
||||||
|
VkDevice mDevice;
|
||||||
|
VmaAllocator mAllocator;
|
||||||
|
VulkanCommands* mCommands;
|
||||||
|
bool mIsTransientAttachment;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
||||||
@@ -119,10 +91,10 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
VulkanStagePool& stagePool);
|
VulkanStagePool& stagePool);
|
||||||
|
|
||||||
// Specialized constructor for internally created textures (e.g. from a swap chain)
|
// Specialized constructor for internally created textures (e.g. from a swap chain)
|
||||||
VulkanTexture(VulkanContext const& context, VkDevice device, VmaAllocator allocator,
|
// The texture will never destroy the given VkImage, but it does manages its subresources.
|
||||||
|
VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||||
VkDeviceMemory memory, VkFormat format, VkSamplerYcbcrConversion conversion,
|
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
|
||||||
TextureUsage tusage, VulkanStagePool& stagePool);
|
TextureUsage tusage, VulkanStagePool& stagePool);
|
||||||
|
|
||||||
// Constructor for creating a texture view for wrt specific mip range
|
// Constructor for creating a texture view for wrt specific mip range
|
||||||
@@ -141,6 +113,11 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
void updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
void updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
|
||||||
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel);
|
uint32_t depth, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t miplevel);
|
||||||
|
|
||||||
|
// Returns the primary image view, which is used for shader sampling.
|
||||||
|
VkImageView getPrimaryImageView() {
|
||||||
|
return getImageView(mPrimaryViewRange, mState->mViewType, mSwizzle);
|
||||||
|
}
|
||||||
|
|
||||||
VkImageViewType getViewType() const {
|
VkImageViewType getViewType() const {
|
||||||
return mState->mViewType;
|
return mState->mViewType;
|
||||||
}
|
}
|
||||||
@@ -155,11 +132,20 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
// time of the call.
|
// time of the call.
|
||||||
VulkanLayout getDefaultLayout() const;
|
VulkanLayout getDefaultLayout() const;
|
||||||
|
|
||||||
// Gets or creates a cached VkImageView for a subresource that can be used as a render
|
// Gets or creates a cached VkImageView for a single subresource that can be used as a render
|
||||||
// target attachment. Unlike the primary image view, this always the identity swizzle.
|
// target attachment. Unlike the primary image view, this always has type VK_IMAGE_VIEW_TYPE_2D
|
||||||
VkImageView getAttachmentView(VkImageSubresourceRange const& range, VkImageViewType type);
|
// and the identity swizzle.
|
||||||
|
VkImageView getAttachmentView(VkImageSubresourceRange range);
|
||||||
|
|
||||||
VkImageView getView(VkImageSubresourceRange const& range);
|
// Gets or creates a cached VkImageView for a single subresource that can be used as a render
|
||||||
|
// target attachment when rendering with multiview.
|
||||||
|
VkImageView getMultiviewAttachmentView(VkImageSubresourceRange range);
|
||||||
|
|
||||||
|
// This is a workaround for the first few frames where we're waiting for the texture to actually
|
||||||
|
// be uploaded. In that case, we bind the sampler to an empty texture, but the corresponding
|
||||||
|
// imageView needs to be of the right type. Hence, we provide an option to indicate the
|
||||||
|
// view type. Swizzle option does not matter in this case.
|
||||||
|
VkImageView getViewForType(VkImageSubresourceRange const& range, VkImageViewType type);
|
||||||
|
|
||||||
VkFormat getVkFormat() const {
|
VkFormat getVkFormat() const {
|
||||||
return mState->mVkFormat;
|
return mState->mVkFormat;
|
||||||
@@ -179,7 +165,7 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isTransientAttachment() const {
|
bool isTransientAttachment() const {
|
||||||
return mState->mUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
return mState->mIsTransientAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getIsProtected() const {
|
bool getIsProtected() const {
|
||||||
@@ -206,11 +192,6 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
// manually (outside of calls to transitionLayout).
|
// manually (outside of calls to transitionLayout).
|
||||||
void setLayout(VkImageSubresourceRange const& range, VulkanLayout newLayout);
|
void setLayout(VkImageSubresourceRange const& range, VulkanLayout newLayout);
|
||||||
|
|
||||||
// This is used in the case of external images and external samplers. AHB might update the
|
|
||||||
// conversion per-frame. This implies that we need to invalidate the view cache when that
|
|
||||||
// happens.
|
|
||||||
void setYcbcrConversion(VkSamplerYcbcrConversion conversion, bool isExternal);
|
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||||
void print() const;
|
void print() const;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "VulkanYcbcrConversionCache.h"
|
|
||||||
|
|
||||||
#include "vulkan/VulkanConstants.h"
|
|
||||||
#include "vulkan/utils/Conversion.h"
|
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#include <vulkan/vulkan_android.h> // for VkExternalFormatANDROID
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace bluevk;
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
VulkanYcbcrConversionCache::VulkanYcbcrConversionCache(VkDevice device)
|
|
||||||
: mDevice(device) {}
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
|
||||||
VulkanYcbcrConversionCache::Params params) noexcept {
|
|
||||||
auto iter = mCache.find(params);
|
|
||||||
if (UTILS_LIKELY(iter != mCache.end())) {
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const& chroma = params.conversion;
|
|
||||||
TextureSwizzle const swizzleArray[] = { chroma.r, chroma.g, chroma.b, chroma.a };
|
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
|
||||||
.format = fvkutils::getVkFormat(params.format),
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
|
||||||
};
|
|
||||||
|
|
||||||
// We could put this in the platform class, but that seems like a bit of an overkill
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
VkExternalFormatANDROID externalFormat = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
|
||||||
.externalFormat = params.externalFormat,
|
|
||||||
};
|
|
||||||
if (params.externalFormat) {
|
|
||||||
conversionInfo.pNext = &externalFormat;
|
|
||||||
conversionInfo.format = VK_FORMAT_UNDEFINED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversion conversion;
|
|
||||||
VkResult result =
|
|
||||||
vkCreateSamplerYcbcrConversion(mDevice, &conversionInfo, nullptr, &conversion);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create Ycbcr Conversion."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
mCache.insert({ params, conversion });
|
|
||||||
return conversion;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanYcbcrConversionCache::terminate() noexcept {
|
|
||||||
for (auto& [param, conv]: mCache) {
|
|
||||||
vkDestroySamplerYcbcrConversion(mDevice, conv, VKALLOC);
|
|
||||||
}
|
|
||||||
mCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
|
||||||
#include <tsl/robin_map.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
// Simple manager for VkSamplerYcbcrConversion objects.
|
|
||||||
class VulkanYcbcrConversionCache {
|
|
||||||
public:
|
|
||||||
struct Params {
|
|
||||||
SamplerYcbcrConversion conversion = {};
|
|
||||||
TextureFormat format = {};
|
|
||||||
uint16_t padding = 0;
|
|
||||||
uint64_t externalFormat = 0;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Params) == 16);
|
|
||||||
|
|
||||||
explicit VulkanYcbcrConversionCache(VkDevice device);
|
|
||||||
VkSamplerYcbcrConversion getConversion(Params params) noexcept;
|
|
||||||
void terminate() noexcept;
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDevice mDevice;
|
|
||||||
|
|
||||||
struct ConversionEqualTo {
|
|
||||||
bool operator()(Params lhs, Params rhs) const noexcept {
|
|
||||||
SamplerYcbcrConversion::EqualTo equal;
|
|
||||||
return equal(lhs.conversion, rhs.conversion) &&
|
|
||||||
lhs.externalFormat == rhs.externalFormat;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
|
||||||
tsl::robin_map<Params, VkSamplerYcbcrConversion, ConversionHashFn, ConversionEqualTo> mCache;
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_VULKANYCBCRCONVERSIONCACHE_H
|
|
||||||
@@ -0,0 +1,504 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "VulkanDescriptorSetManager.h"
|
||||||
|
|
||||||
|
#include "vulkan/VulkanCommands.h"
|
||||||
|
#include "vulkan/VulkanHandles.h"
|
||||||
|
#include "vulkan/VulkanConstants.h"
|
||||||
|
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
|
||||||
|
using DescriptorCount = VulkanDescriptorSetLayout::Count;
|
||||||
|
using DescriptorSetLayoutArray = VulkanDescriptorSetManager::DescriptorSetLayoutArray;
|
||||||
|
using BitmaskGroupHashFn = utils::hash::MurmurHashFn<BitmaskGroup>;
|
||||||
|
struct BitmaskGroupEqual {
|
||||||
|
bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const {
|
||||||
|
return k1 == k2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
||||||
|
// example, a layout of
|
||||||
|
// 'A' =>
|
||||||
|
// layout(binding = 0, set = 1) uniform {};
|
||||||
|
// layout(binding = 1, set = 1) sampler1;
|
||||||
|
// layout(binding = 2, set = 1) sampler2;
|
||||||
|
//
|
||||||
|
// would be equivalent to
|
||||||
|
// 'B' =>
|
||||||
|
// layout(binding = 1, set = 2) uniform {};
|
||||||
|
// layout(binding = 2, set = 2) sampler2;
|
||||||
|
// layout(binding = 3, set = 2) sampler3;
|
||||||
|
//
|
||||||
|
// TODO: we might do better if we understand the types of unique layouts and can combine them in a
|
||||||
|
// single pool without too much waste.
|
||||||
|
class DescriptorPool {
|
||||||
|
public:
|
||||||
|
DescriptorPool(VkDevice device, DescriptorCount const& count, uint16_t capacity)
|
||||||
|
: mDevice(device),
|
||||||
|
mCount(count),
|
||||||
|
mCapacity(capacity),
|
||||||
|
mSize(0),
|
||||||
|
mUnusedCount(0) {
|
||||||
|
DescriptorCount const actual = mCount * capacity;
|
||||||
|
VkDescriptorPoolSize sizes[4];
|
||||||
|
uint8_t npools = 0;
|
||||||
|
if (actual.ubo) {
|
||||||
|
sizes[npools++] = {
|
||||||
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = actual.ubo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (actual.dynamicUbo) {
|
||||||
|
sizes[npools++] = {
|
||||||
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||||
|
.descriptorCount = actual.dynamicUbo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (actual.sampler) {
|
||||||
|
sizes[npools++] = {
|
||||||
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.descriptorCount = actual.sampler,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (actual.inputAttachment) {
|
||||||
|
sizes[npools++] = {
|
||||||
|
.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||||
|
.descriptorCount = actual.inputAttachment,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
VkDescriptorPoolCreateInfo info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.maxSets = capacity,
|
||||||
|
.poolSizeCount = npools,
|
||||||
|
.pPoolSizes = sizes,
|
||||||
|
};
|
||||||
|
vkCreateDescriptorPool(mDevice, &info, VKALLOC, &mPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorPool(DescriptorPool const&) = delete;
|
||||||
|
DescriptorPool& operator=(DescriptorPool const&) = delete;
|
||||||
|
|
||||||
|
~DescriptorPool() {
|
||||||
|
vkDestroyDescriptorPool(mDevice, mPool, VKALLOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t const& capacity() {
|
||||||
|
return mCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A convenience method for checking if this pool can allocate sets for a given layout.
|
||||||
|
inline bool canAllocate(DescriptorCount const& count) {
|
||||||
|
return count == mCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSet obtainSet(VkDescriptorSetLayout vklayout) {
|
||||||
|
auto itr = findSets(vklayout);
|
||||||
|
if (itr != mUnused.end()) {
|
||||||
|
// If we don't have any unused, then just return an empty handle.
|
||||||
|
if (itr->second.empty()) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
std::vector<VkDescriptorSet>& sets = itr->second;
|
||||||
|
auto set = sets.back();
|
||||||
|
sets.pop_back();
|
||||||
|
mUnusedCount--;
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
if (mSize + 1 > mCapacity) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
// Creating a new set
|
||||||
|
VkDescriptorSetLayout layouts[1] = {vklayout};
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.descriptorPool = mPool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = layouts,
|
||||||
|
};
|
||||||
|
VkDescriptorSet vkSet;
|
||||||
|
UTILS_UNUSED VkResult result = vkAllocateDescriptorSets(mDevice, &allocInfo, &vkSet);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "Failed to allocate descriptor set code=" << result << " size=" << mSize
|
||||||
|
<< " capacity=" << mCapacity << " count=" << mUnusedCount;
|
||||||
|
mSize++;
|
||||||
|
return vkSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recycle(VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
||||||
|
// We are recycling - release the set back into the pool. Note that the
|
||||||
|
// vk handle has not changed, but we need to change the backend handle to allow
|
||||||
|
// for proper refcounting of resources referenced in this set.
|
||||||
|
auto itr = findSets(vklayout);
|
||||||
|
if (itr != mUnused.end()) {
|
||||||
|
itr->second.push_back(vkSet);
|
||||||
|
} else {
|
||||||
|
mUnused.push_back(std::make_pair(vklayout, std::vector<VkDescriptorSet> {vkSet}));
|
||||||
|
}
|
||||||
|
mUnusedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using UnusedSets = std::pair<VkDescriptorSetLayout, std::vector<VkDescriptorSet>>;
|
||||||
|
using UnusedSetMap = std::vector<UnusedSets>;
|
||||||
|
|
||||||
|
inline UnusedSetMap::iterator findSets(VkDescriptorSetLayout vklayout) {
|
||||||
|
return std::find_if(mUnused.begin(), mUnused.end(), [vklayout](auto const& value) {
|
||||||
|
return value.first == vklayout;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDevice mDevice;
|
||||||
|
VkDescriptorPool mPool;
|
||||||
|
DescriptorCount const mCount;
|
||||||
|
uint16_t const mCapacity;
|
||||||
|
|
||||||
|
// Tracks the number of allocated descriptor sets.
|
||||||
|
uint16_t mSize;
|
||||||
|
// Tracks the number of in-use descriptor sets.
|
||||||
|
uint16_t mUnusedCount;
|
||||||
|
|
||||||
|
// This maps a layout to a list of descriptor sets allocated for that layout.
|
||||||
|
UnusedSetMap mUnused;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Key>
|
||||||
|
struct Equal {
|
||||||
|
bool operator()(Key const& k1, Key const& k2) const {
|
||||||
|
return 0 == memcmp((const void*) &k1, (const void*) &k2, sizeof(Key));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Bitmask>
|
||||||
|
uint32_t createBindings(VkDescriptorSetLayoutBinding* toBind, uint32_t count, VkDescriptorType type,
|
||||||
|
Bitmask const& mask) {
|
||||||
|
Bitmask alreadySeen;
|
||||||
|
mask.forEachSetBit([&](size_t index) {
|
||||||
|
VkShaderStageFlags stages = 0;
|
||||||
|
uint32_t binding = 0;
|
||||||
|
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
|
||||||
|
binding = (uint32_t) index;
|
||||||
|
stages |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
|
||||||
|
if (mask.test(fragIndex)) {
|
||||||
|
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
alreadySeen.set(fragIndex);
|
||||||
|
}
|
||||||
|
} else if (!alreadySeen.test(index)) {
|
||||||
|
// We are in fragment stage bits
|
||||||
|
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
|
||||||
|
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stages) {
|
||||||
|
toBind[count++] = {
|
||||||
|
.binding = binding,
|
||||||
|
.descriptorType = type,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = stages,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDescriptorSetLayout createLayout(VkDevice device, BitmaskGroup const& bitmaskGroup) {
|
||||||
|
// Note that the following *needs* to be static so that VkDescriptorSetLayoutCreateInfo will not
|
||||||
|
// refer to stack memory.
|
||||||
|
VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS];
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||||
|
bitmaskGroup.dynamicUbo);
|
||||||
|
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmaskGroup.ubo);
|
||||||
|
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
bitmaskGroup.sampler);
|
||||||
|
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||||
|
bitmaskGroup.inputAttachment);
|
||||||
|
|
||||||
|
assert_invariant(count != 0 && "Need at least one binding for descriptor set layout.");
|
||||||
|
VkDescriptorSetLayoutCreateInfo dlinfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.bindingCount = count,
|
||||||
|
.pBindings = toBind,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayout layout;
|
||||||
|
vkCreateDescriptorSetLayout(device, &dlinfo, VKALLOC, &layout);
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
// This is an ever-expanding pool of sets where it
|
||||||
|
// 1. Keeps a list of smaller pools of different layout-dimensions.
|
||||||
|
// 2. Will add a pool if existing pool are not compatible with the requested layout o runs out.
|
||||||
|
class VulkanDescriptorSetManager::DescriptorInfinitePool {
|
||||||
|
private:
|
||||||
|
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
|
||||||
|
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DescriptorInfinitePool(VkDevice device)
|
||||||
|
: mDevice(device) {}
|
||||||
|
|
||||||
|
VkDescriptorSet obtainSet(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
|
auto const vklayout = layout->getVkLayout();
|
||||||
|
DescriptorPool* sameTypePool = nullptr;
|
||||||
|
for (auto& pool: mPools) {
|
||||||
|
if (!pool->canAllocate(layout->count)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
if (!sameTypePool || sameTypePool->capacity() < pool->capacity()) {
|
||||||
|
sameTypePool = pool.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t capacity = EXPECTED_SET_COUNT;
|
||||||
|
if (sameTypePool) {
|
||||||
|
// Exponentially increase the size of the pool to ensure we don't hit this too often.
|
||||||
|
capacity = std::ceil(sameTypePool->capacity() * SET_COUNT_GROWTH_FACTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to increase the set of pools by one.
|
||||||
|
mPools.push_back(std::make_unique<DescriptorPool>(mDevice,
|
||||||
|
DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity));
|
||||||
|
auto& pool = mPools.back();
|
||||||
|
auto ret = pool->obtainSet(vklayout);
|
||||||
|
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recycle(DescriptorCount const& count, VkDescriptorSetLayout vklayout,
|
||||||
|
VkDescriptorSet vkSet) {
|
||||||
|
for (auto& pool: mPools) {
|
||||||
|
if (!pool->canAllocate(count)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pool->recycle(vklayout, vkSet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice mDevice;
|
||||||
|
std::vector<std::unique_ptr<DescriptorPool>> mPools;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanDescriptorSetManager::DescriptorSetLayoutManager {
|
||||||
|
public:
|
||||||
|
DescriptorSetLayoutManager(VkDevice device)
|
||||||
|
: mDevice(device) {}
|
||||||
|
|
||||||
|
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks) {
|
||||||
|
if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) {
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
auto vklayout = createLayout(mDevice, bitmasks);
|
||||||
|
mVkLayouts[bitmasks] = vklayout;
|
||||||
|
return vklayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DescriptorSetLayoutManager() {
|
||||||
|
for (auto& itr: mVkLayouts) {
|
||||||
|
vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice mDevice;
|
||||||
|
tsl::robin_map<BitmaskGroup, VkDescriptorSetLayout, BitmaskGroupHashFn, BitmaskGroupEqual>
|
||||||
|
mVkLayouts;
|
||||||
|
};
|
||||||
|
|
||||||
|
VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device,
|
||||||
|
fvkmemory::ResourceManager* resourceManager)
|
||||||
|
: mDevice(device),
|
||||||
|
mResourceManager(resourceManager),
|
||||||
|
mLayoutManager(std::make_unique<DescriptorSetLayoutManager>(device)),
|
||||||
|
mDescriptorPool(std::make_unique<DescriptorInfinitePool>(device)) {}
|
||||||
|
|
||||||
|
VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default;
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::terminate() noexcept{
|
||||||
|
mLayoutManager.reset();
|
||||||
|
mDescriptorPool.reset();
|
||||||
|
clearHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind() is not really binding the set but just stashing until we have all the info
|
||||||
|
// (pipelinelayout).
|
||||||
|
void VulkanDescriptorSetManager::bind(uint8_t setIndex,
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
|
set->setOffsets(std::move(offsets));
|
||||||
|
mStashedSets[setIndex] = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::unbind(uint8_t setIndex) {
|
||||||
|
mStashedSets[setIndex] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands,
|
||||||
|
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
|
||||||
|
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
||||||
|
// actual set of sets that *needs* to be bound.
|
||||||
|
fvkutils::DescriptorSetMask curMask = setMask;
|
||||||
|
|
||||||
|
auto& updateSets = mStashedSets;
|
||||||
|
auto& lastBoundSets = mLastBoundInfo.boundSets;
|
||||||
|
|
||||||
|
setMask.forEachSetBit([&](size_t index) {
|
||||||
|
if (!updateSets[index] || updateSets[index] == lastBoundSets[index]) {
|
||||||
|
curMask.unset(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (curMask.none() &&
|
||||||
|
(mLastBoundInfo.pipelineLayout == pipelineLayout && mLastBoundInfo.setMask == setMask &&
|
||||||
|
mLastBoundInfo.boundSets == updateSets)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) {
|
||||||
|
// This code actually binds the descriptor sets.
|
||||||
|
auto set = updateSets[index];
|
||||||
|
VkCommandBuffer const cmdbuffer = commands->buffer();
|
||||||
|
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
|
||||||
|
1, &set->vkSet, set->uniqueDynamicUboCount, set->getOffsets()->data());
|
||||||
|
commands->acquire(set);
|
||||||
|
});
|
||||||
|
|
||||||
|
mStashedSets = {};
|
||||||
|
|
||||||
|
mLastBoundInfo = {
|
||||||
|
pipelineLayout,
|
||||||
|
setMask,
|
||||||
|
updateSets,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
|
||||||
|
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
||||||
|
VkDescriptorBufferInfo const info = {
|
||||||
|
.buffer = bufferObject->buffer.getGpuBuffer(),
|
||||||
|
.offset = offset,
|
||||||
|
.range = size,
|
||||||
|
};
|
||||||
|
VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
|
||||||
|
if (set->dynamicUboMask.test(binding)) {
|
||||||
|
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
|
}
|
||||||
|
VkWriteDescriptorSet const descriptorWrite = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.dstSet = set->vkSet,
|
||||||
|
.dstBinding = binding,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = type,
|
||||||
|
.pBufferInfo = &info,
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
||||||
|
set->acquire(bufferObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
||||||
|
VkSampler sampler) noexcept {
|
||||||
|
VkDescriptorImageInfo info{
|
||||||
|
.sampler = sampler,
|
||||||
|
};
|
||||||
|
VkImageSubresourceRange const range = texture->getPrimaryViewRange();
|
||||||
|
VkImageViewType const expectedType = texture->getViewType();
|
||||||
|
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
|
||||||
|
expectedType == VK_IMAGE_VIEW_TYPE_2D) {
|
||||||
|
// If the sampler is part of a mipmapped depth texture, where one of the level *can* be
|
||||||
|
// an attachment, then the sampler for this texture has the same view properties as a
|
||||||
|
// view for an attachment. Therefore, we can use getAttachmentView to get a
|
||||||
|
// corresponding VkImageView.
|
||||||
|
info.imageView = texture->getAttachmentView(range);
|
||||||
|
} else {
|
||||||
|
info.imageView = texture->getViewForType(range, expectedType);
|
||||||
|
}
|
||||||
|
info.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout());
|
||||||
|
VkWriteDescriptorSet const descriptorWrite = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.dstSet = set->vkSet,
|
||||||
|
.dstBinding = binding,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.pImageInfo = &info,
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
||||||
|
set->acquire(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::updateInputAttachment(
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
VulkanAttachment const& attachment) noexcept {
|
||||||
|
// TOOD: fill-in this region
|
||||||
|
}
|
||||||
|
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetManager::createSet(
|
||||||
|
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
|
auto const vkSet = mDescriptorPool->obtainSet(layout);
|
||||||
|
auto const& count = layout->count;
|
||||||
|
auto const vklayout = layout->getVkLayout();
|
||||||
|
return fvkmemory::resource_ptr<VulkanDescriptorSet>::make(mResourceManager, handle, vkSet,
|
||||||
|
layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
|
||||||
|
[vkSet, count, vklayout, this](VulkanDescriptorSet*) {
|
||||||
|
// Note that mDescriptorPool could be gone due to terminate (when the backend shuts
|
||||||
|
// down).
|
||||||
|
if (mDescriptorPool) {
|
||||||
|
mDescriptorPool->recycle(count, vklayout, vkSet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::initVkLayout(
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
|
layout->setVkLayout(mLayoutManager->getVkLayout(layout->bitmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSetManager::clearHistory() {
|
||||||
|
mStashedSets = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
|
|
||||||
|
#include "vulkan/VulkanHandles.h"
|
||||||
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
|
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/Program.h>
|
||||||
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include <utils/bitset.h>
|
||||||
|
|
||||||
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
// [GDSR]: Great-Descriptor-Set-Refactor: As of 03/20/24, the Filament frontend is planning to
|
||||||
|
// introduce descriptor set. This PR will arrive before that change is complete. As such, some of
|
||||||
|
// the methods introduced here will be obsolete, and certain logic will be generalized.
|
||||||
|
|
||||||
|
// Abstraction over the pool and the layout cache.
|
||||||
|
class VulkanDescriptorSetManager {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
|
||||||
|
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
|
||||||
|
|
||||||
|
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
||||||
|
|
||||||
|
VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||||
|
~VulkanDescriptorSetManager();
|
||||||
|
|
||||||
|
void terminate() noexcept;
|
||||||
|
|
||||||
|
void updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
||||||
|
fvkmemory::resource_ptr<VulkanBufferObject> bufferObject, VkDeviceSize offset,
|
||||||
|
VkDeviceSize size) noexcept;
|
||||||
|
|
||||||
|
void updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set, uint8_t binding,
|
||||||
|
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
|
||||||
|
|
||||||
|
void updateInputAttachment(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
VulkanAttachment const& attachment) noexcept;
|
||||||
|
|
||||||
|
void bind(uint8_t setIndex, fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
|
backend::DescriptorSetOffsetArray&& offsets);
|
||||||
|
|
||||||
|
void unbind(uint8_t setIndex);
|
||||||
|
|
||||||
|
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
|
||||||
|
fvkutils::DescriptorSetMask const& setMask);
|
||||||
|
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
||||||
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
|
void initVkLayout(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
|
void clearHistory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class DescriptorSetLayoutManager;
|
||||||
|
class DescriptorInfinitePool;
|
||||||
|
|
||||||
|
using DescriptorSetArray =
|
||||||
|
std::array<fvkmemory::resource_ptr<VulkanDescriptorSet>, UNIQUE_DESCRIPTOR_SET_COUNT>;
|
||||||
|
|
||||||
|
VkDevice mDevice;
|
||||||
|
fvkmemory::ResourceManager* mResourceManager;
|
||||||
|
std::unique_ptr<DescriptorSetLayoutManager> mLayoutManager;
|
||||||
|
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
|
||||||
|
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
||||||
|
DescriptorSetArray mStashedSets = {};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
fvkutils::DescriptorSetMask setMask;
|
||||||
|
DescriptorSetArray boundSets = {};
|
||||||
|
} mLastBoundInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
}// namespace filament::backend
|
||||||
|
|
||||||
|
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
+1
-2
@@ -17,8 +17,7 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include <vulkan/VulkanHandles.h>
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
@@ -211,7 +211,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
|||||||
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
|
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
|
||||||
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
||||||
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
||||||
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
|
|
||||||
#endif
|
#endif
|
||||||
// MoltenVk is the only non-conformant implementation we're interested in.
|
// MoltenVk is the only non-conformant implementation we're interested in.
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@@ -327,9 +326,7 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||||
VkPhysicalDeviceFeatures2 const& features,
|
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
|
||||||
VkPhysicalDeviceVulkan11Features const& vk11Features,
|
|
||||||
uint32_t graphicsQueueFamilyIndex,
|
|
||||||
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
|
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
|
||||||
bool requestImageView2DOn3DImage) {
|
bool requestImageView2DOn3DImage) {
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
@@ -362,28 +359,14 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
|||||||
|
|
||||||
// We could simply enable all supported features, but since that may have performance
|
// We could simply enable all supported features, but since that may have performance
|
||||||
// consequences let's just enable the features we need.
|
// consequences let's just enable the features we need.
|
||||||
VkPhysicalDeviceFeatures enabledFeatures = {
|
VkPhysicalDeviceFeatures enabledFeatures{
|
||||||
.depthClamp = features.features.depthClamp,
|
.depthClamp = features.features.depthClamp,
|
||||||
.samplerAnisotropy = features.features.samplerAnisotropy,
|
.samplerAnisotropy = features.features.samplerAnisotropy,
|
||||||
.textureCompressionETC2 = features.features.textureCompressionETC2,
|
.textureCompressionETC2 = features.features.textureCompressionETC2,
|
||||||
.textureCompressionBC = features.features.textureCompressionBC,
|
.textureCompressionBC = features.features.textureCompressionBC,
|
||||||
.shaderClipDistance = features.features.shaderClipDistance,
|
.shaderClipDistance = features.features.shaderClipDistance,
|
||||||
};
|
};
|
||||||
|
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
||||||
VkPhysicalDeviceFeatures2 enabledFeatures2 = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
|
||||||
.features = enabledFeatures,
|
|
||||||
};
|
|
||||||
chainStruct(&deviceCreateInfo, &enabledFeatures2);
|
|
||||||
|
|
||||||
VkPhysicalDeviceVulkan11Features enabledVk11Features = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
|
|
||||||
.multiview = vk11Features.multiview,
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
.samplerYcbcrConversion = vk11Features.samplerYcbcrConversion,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
chainStruct(&deviceCreateInfo, &enabledVk11Features);
|
|
||||||
|
|
||||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
||||||
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
||||||
@@ -400,7 +383,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
|||||||
|
|
||||||
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||||
.multiview = vk11Features.multiview,
|
.multiview = VK_TRUE,
|
||||||
.multiviewGeometryShader = VK_FALSE,
|
.multiviewGeometryShader = VK_FALSE,
|
||||||
.multiviewTessellationShader = VK_FALSE,
|
.multiviewTessellationShader = VK_FALSE,
|
||||||
};
|
};
|
||||||
@@ -751,9 +734,12 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
|
||||||
};
|
};
|
||||||
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
|
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
|
||||||
chainStruct(&context.mPhysicalDeviceFeatures, &context.mPhysicalDeviceVk11Features);
|
|
||||||
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
|
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
|
||||||
|
|
||||||
|
// We know we need to allocate the protected version of the VK objects
|
||||||
|
context.mProtectedMemorySupported =
|
||||||
|
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
|
||||||
|
|
||||||
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
||||||
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
|
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
|
||||||
vkGetPhysicalDeviceProperties2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceProperties);
|
vkGetPhysicalDeviceProperties2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceProperties);
|
||||||
@@ -773,10 +759,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
mImpl->mGraphicsQueueIndex = 0;
|
mImpl->mGraphicsQueueIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We know we need to allocate the protected version of the VK objects
|
|
||||||
context.mProtectedMemorySupported =
|
|
||||||
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
|
|
||||||
|
|
||||||
if (context.mProtectedMemorySupported) {
|
if (context.mProtectedMemorySupported) {
|
||||||
mImpl->mProtectedGraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(
|
mImpl->mProtectedGraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(
|
||||||
mImpl->mPhysicalDevice, (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
|
mImpl->mPhysicalDevice, (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
|
||||||
@@ -813,8 +795,8 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mImpl->mDevice == VK_NULL_HANDLE) {
|
if (mImpl->mDevice == VK_NULL_HANDLE) {
|
||||||
mImpl->mDevice = createLogicalDevice(mImpl->mPhysicalDevice,
|
mImpl->mDevice =
|
||||||
context.mPhysicalDeviceFeatures, context.mPhysicalDeviceVk11Features,
|
createLogicalDevice(mImpl->mPhysicalDevice, context.mPhysicalDeviceFeatures,
|
||||||
mImpl->mGraphicsQueueFamilyIndex, mImpl->mProtectedGraphicsQueueFamilyIndex,
|
mImpl->mGraphicsQueueFamilyIndex, mImpl->mProtectedGraphicsQueueFamilyIndex,
|
||||||
deviceExts, requestPortabilitySubsetImageView2DOn3DImage);
|
deviceExts, requestPortabilitySubsetImageView2DOn3DImage);
|
||||||
}
|
}
|
||||||
@@ -844,10 +826,12 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
if (!mImpl->mSharedContext) {
|
if (!mImpl->mSharedContext) {
|
||||||
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||||
|
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||||
} else {
|
} else {
|
||||||
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
||||||
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
||||||
context.mDebugMarkersSupported = scontext->debugMarkersSupported;
|
context.mDebugMarkersSupported = scontext->debugMarkersSupported;
|
||||||
|
context.mMultiviewEnabled = scontext->multiviewSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the availability of lazily allocated memory
|
// Check the availability of lazily allocated memory
|
||||||
@@ -999,32 +983,10 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
||||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata) {
|
||||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata);
|
||||||
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata, memoryTypeIndex,
|
|
||||||
usage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSampler(SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler, uint32_t internalFormat) {
|
|
||||||
return createExternalSamplerImpl(mImpl->mDevice, chroma, sampler, internalFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chroma,
|
|
||||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
|
||||||
VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range,
|
|
||||||
viewType, swizzle);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
|
|
||||||
return getSwapchainInstanceExtensionsImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
|
||||||
VkInstance instance, uint64_t flags) const noexcept {
|
|
||||||
return createVkSurfaceKHRImpl(nativeWindow, instance, flags);
|
|
||||||
}
|
|
||||||
#undef SWAPCHAIN_RET_FUNC
|
#undef SWAPCHAIN_RET_FUNC
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -13,16 +13,15 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||||
#include <private/backend/BackendUtilsAndroid.h>
|
#include <private/backend/BackendUtilsAndroid.h>
|
||||||
|
|
||||||
#include "vulkan/VulkanConstants.h"
|
#include "vulkan/VulkanConstants.h"
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include "vulkan/utils/Image.h"
|
|
||||||
#include "vulkan/utils/Conversion.h"
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -137,8 +136,7 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
||||||
VulkanPlatform::ExternalImageMetadata const& metadata, uint32_t memoryTypeIndex,
|
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
||||||
VkImageUsageFlags usage) {
|
|
||||||
VulkanPlatform::ImageData data;
|
VulkanPlatform::ImageData data;
|
||||||
|
|
||||||
// if external format we need to specifiy it in the allocation
|
// if external format we need to specifiy it in the allocation
|
||||||
@@ -147,8 +145,8 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
const VkExternalFormatANDROID externalFormat = {
|
const VkExternalFormatANDROID externalFormat = {
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
// pass down the format (external means we don't have it VK defined)
|
.externalFormat = metadata
|
||||||
.externalFormat = metadata.externalFormat,
|
.externalFormat,// pass down the format (external means we don't have it VK defined)
|
||||||
};
|
};
|
||||||
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||||
@@ -156,7 +154,7 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkImageCreateInfo imageInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
|
||||||
imageInfo.pNext = &externalCreateInfo;
|
imageInfo.pNext = &externalCreateInfo;
|
||||||
imageInfo.format = metadata.format;
|
imageInfo.format = metadata.format;
|
||||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
@@ -167,8 +165,10 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
};
|
};
|
||||||
imageInfo.mipLevels = 1;
|
imageInfo.mipLevels = 1;
|
||||||
imageInfo.arrayLayers = metadata.layers;
|
imageInfo.arrayLayers = metadata.layers;
|
||||||
imageInfo.samples = metadata.samples;
|
imageInfo.usage = metadata.usage;
|
||||||
imageInfo.usage = usage;
|
// In the unprotected case add R/W capabilities
|
||||||
|
if (metadata.isProtected == false)
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
|
||||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
@@ -186,12 +186,10 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
.image = data.first,
|
.image = data.first,
|
||||||
.buffer = VK_NULL_HANDLE,
|
.buffer = VK_NULL_HANDLE,
|
||||||
};
|
};
|
||||||
VkMemoryAllocateInfo allocInfo = {
|
VkMemoryAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
||||||
.pNext = &memoryDedicatedAllocateInfo,
|
.pNext = &memoryDedicatedAllocateInfo,
|
||||||
.allocationSize = metadata.allocationSize,
|
.allocationSize = metadata.allocationSize,
|
||||||
.memoryTypeIndex = memoryTypeIndex,
|
.memoryTypeIndex = metadata.memoryTypeBits};
|
||||||
};
|
|
||||||
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
||||||
@@ -199,12 +197,14 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace
|
} // namespace
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
namespace fvkandroid {
|
||||||
|
|
||||||
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||||
AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
|
||||||
|
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||||
|
bool sRGB) noexcept {
|
||||||
if (__builtin_available(android 26, *)) {
|
if (__builtin_available(android 26, *)) {
|
||||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||||
@@ -223,23 +223,12 @@ Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
|||||||
return Platform::ExternalImageHandle{};
|
return Platform::ExternalImageHandle{};
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
|
} // namespace fvkandroid
|
||||||
ExternalImageHandleRef externalImage) const noexcept {
|
|
||||||
auto const* fvkExternalImage =
|
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
|
||||||
|
|
||||||
return {
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||||
.width = fvkExternalImage->width,
|
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||||
.height = fvkExternalImage->height,
|
|
||||||
.format = fvkExternalImage->format,
|
|
||||||
.usage = fvkExternalImage->usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
|
|
||||||
ExternalImageHandleRef externalImage) {
|
|
||||||
auto const* fvkExternalImage =
|
auto const* fvkExternalImage =
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
|
|
||||||
ExternalImageMetadata metadata;
|
ExternalImageMetadata metadata;
|
||||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||||
@@ -253,8 +242,10 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
std::tie(metadata.format, metadata.usage) =
|
std::tie(metadata.format, metadata.usage) =
|
||||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||||
}
|
}
|
||||||
|
// In the unprotected case add R/W capabilities
|
||||||
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
if (metadata.isProtected == false) {
|
||||||
|
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
||||||
@@ -264,7 +255,7 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||||
.pNext = &formatInfo,
|
.pNext = &formatInfo,
|
||||||
};
|
};
|
||||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(getDevice(), buffer, &properties);
|
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||||
<< static_cast<int32_t>(result);
|
<< static_cast<int32_t>(result);
|
||||||
@@ -279,137 +270,26 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
auto const* fvkExternalImage =
|
auto const* fvkExternalImage =
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
|
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata);
|
||||||
memoryTypeIndex, usage);
|
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||||
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, SamplerYcbcrConversion chroma,
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
|
||||||
VkImageViewType viewType, VkComponentMapping swizzle){
|
|
||||||
VkExternalFormatANDROID externalFormat = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
|
||||||
.externalFormat = internalFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
|
||||||
.pNext = &externalFormat,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
|
||||||
};
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
|
||||||
nullptr, &conversion);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create Ycbcr Conversion."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.conversion = conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.pNext = &samplerYcbcrConversionInfo,
|
|
||||||
.flags = 0,
|
|
||||||
.image = image,
|
|
||||||
.viewType = viewType,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.components = swizzle,
|
|
||||||
.subresourceRange = range,
|
|
||||||
};
|
|
||||||
VkImageView imageView;
|
|
||||||
result = vkCreateImageView(device, &viewInfo, VKALLOC, &imageView);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create VkImageView."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(
|
|
||||||
VkDevice device, SamplerYcbcrConversion chroma, SamplerParams params,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
VkExternalFormatANDROID externalFormat = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
|
||||||
.externalFormat = internalFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
|
||||||
.pNext = &externalFormat,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
|
||||||
};
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
|
||||||
nullptr, &conversion);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create Ycbcr Conversion."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.conversion = conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
||||||
.pNext = &samplerYcbcrConversionInfo,
|
|
||||||
.magFilter = fvkutils::getFilter(params.filterMag),
|
|
||||||
.minFilter = fvkutils::getFilter(params.filterMin),
|
|
||||||
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
|
||||||
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
|
||||||
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
|
||||||
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
|
||||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
|
||||||
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
|
||||||
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
|
||||||
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
|
||||||
.minLod = 0.0f,
|
|
||||||
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
|
||||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
||||||
.unnormalizedCoordinates = VK_FALSE,
|
|
||||||
};
|
|
||||||
VkSampler sampler;
|
|
||||||
result = vkCreateSampler(device, &samplerInfo, VKALLOC, &sampler);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create sampler."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
return sampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
|
|
||||||
return {
|
return {
|
||||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) const noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
|
|
||||||
@@ -421,26 +301,6 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
|
|||||||
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
|
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkCreateAndroidSurfaceKHR with error=" << static_cast<int32_t>(result);
|
<< "vkCreateAndroidSurfaceKHR with error=" << static_cast<int32_t>(result);
|
||||||
return { surface, extent };
|
return {surface, extent};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated platform dependent helper methods
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; }
|
|
||||||
|
|
||||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
|
||||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
|
||||||
return ExternalImageMetadata{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
|
||||||
ExternalImageHandleRef externalImage, VkDevice device,
|
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
|
||||||
return ImageData{};
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
|
||||||
return SurfaceBundle{};
|
|
||||||
}
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
|
|||||||
@@ -24,21 +24,41 @@
|
|||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
// Platform specific includes and defines
|
// Platform specific includes and defines
|
||||||
#include <Cocoa/Cocoa.h>
|
#if defined(__APPLE__)
|
||||||
#import <Metal/Metal.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#import <QuartzCore/CAMetalLayer.h>
|
#import <Metal/Metal.h>
|
||||||
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
#ifndef VK_MVK_macos_surface
|
#ifndef VK_MVK_macos_surface
|
||||||
#error VK_MVK_macos_surface is not defined
|
#error VK_MVK_macos_surface is not defined
|
||||||
|
#endif
|
||||||
|
#elif defined(FILAMENT_IOS)
|
||||||
|
// Metal is not available when building for the iOS simulator on Desktop.
|
||||||
|
#define METAL_AVAILABLE __has_include(<QuartzCore/CAMetalLayer.h>)
|
||||||
|
#if METAL_AVAILABLE
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VK_MVK_ios_surface
|
||||||
|
#error VK_MVK_ios_surface is not defined
|
||||||
|
#endif
|
||||||
|
#define METALVIEW_TAG 255
|
||||||
|
#else
|
||||||
|
#error Not a supported Apple + Vulkan platform
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
ExtensionSet const ret = {
|
ExtensionSet const ret = {
|
||||||
|
#if defined(__APPLE__)
|
||||||
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
|
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
|
||||||
|
#elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE)
|
||||||
|
VK_MVK_IOS_SURFACE_EXTENSION_NAME,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -50,26 +70,14 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
|||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, VkDevice device,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
#if defined(__APPLE__)
|
||||||
NSView* nsview = (__bridge NSView*) nativeWindow;
|
NSView* nsview = (__bridge NSView*) nativeWindow;
|
||||||
FILAMENT_CHECK_POSTCONDITION(nsview) << "Unable to obtain Metal-backed NSView.";
|
FILAMENT_CHECK_POSTCONDITION(nsview) << "Unable to obtain Metal-backed NSView.";
|
||||||
|
|
||||||
@@ -83,6 +91,21 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativ
|
|||||||
(VkSurfaceKHR*) &surface);
|
(VkSurfaceKHR*) &surface);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkCreateMacOSSurfaceMVK. error=" << static_cast<int32_t>(result);
|
<< "vkCreateMacOSSurfaceMVK. error=" << static_cast<int32_t>(result);
|
||||||
|
#elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE)
|
||||||
|
CAMetalLayer* metalLayer = (CAMetalLayer*) nativeWindow;
|
||||||
|
// Create the VkSurface.
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(vkCreateIOSSurfaceMVK)
|
||||||
|
<< "Unable to load vkCreateIOSSurfaceMVK function.";
|
||||||
|
VkIOSSurfaceCreateInfoMVK createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
|
||||||
|
createInfo.pNext = NULL;
|
||||||
|
createInfo.flags = 0;
|
||||||
|
createInfo.pView = metalLayer;
|
||||||
|
VkResult result = vkCreateIOSSurfaceMVK((VkInstance) instance, &createInfo, VKALLOC,
|
||||||
|
(VkSurfaceKHR*) &surface);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
|
<< "vkCreateIOSSurfaceMVK failed. error=" << static_cast<int32_t>(result);
|
||||||
|
#endif
|
||||||
return std::make_tuple(surface, VkExtent2D{});
|
return std::make_tuple(surface, VkExtent2D{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,24 +91,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
|||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, VkDevice device,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
|
||||||
VulkanPlatform::ExtensionSet const ret = {
|
VulkanPlatform::ExtensionSet const ret = {
|
||||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||||
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
||||||
@@ -126,7 +113,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_VULKANSWAPCHAIN_IMPL_H
|
#define TNT_FILAMENT_BACKEND_VULKANSWAPCHAIN_IMPL_H
|
||||||
|
|
||||||
#include "vulkan/VulkanContext.h"
|
#include "vulkan/VulkanContext.h"
|
||||||
#include "vulkan/VulkanConstants.h"
|
|
||||||
|
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|||||||
@@ -588,79 +588,6 @@ VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]) {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFilter getFilter(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFilter getFilter(SamplerMagFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMagFilter::NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMagFilter::LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case SamplerWrapMode::REPEAT:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
case SamplerWrapMode::CLAMP_TO_EDGE:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
case SamplerWrapMode::MIRRORED_REPEAT:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBool32 getCompareEnable(SamplerCompareMode mode) {
|
|
||||||
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getMaxLod(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
|
||||||
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
|
||||||
return 0.25f;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_LOD_CLAMP_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
||||||
VkShaderStageFlags flags = 0x0;
|
VkShaderStageFlags flags = 0x0;
|
||||||
if (any(stageFlags & ShaderStageFlags::VERTEX)) flags |= VK_SHADER_STAGE_VERTEX_BIT;
|
if (any(stageFlags & ShaderStageFlags::VERTEX)) flags |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
@@ -668,111 +595,4 @@ VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(
|
|
||||||
SamplerYcbcrModelConversion model) {
|
|
||||||
switch (model) {
|
|
||||||
case SamplerYcbcrModelConversion::RGB_IDENTITY:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_IDENTITY:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_709:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_601:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_2020:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range) {
|
|
||||||
switch (range) {
|
|
||||||
case SamplerYcbcrRange::ITU_FULL:
|
|
||||||
return VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
|
|
||||||
case SamplerYcbcrRange::ITU_NARROW:
|
|
||||||
return VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkChromaLocation getChromaLocation(ChromaLocation loc) {
|
|
||||||
switch (loc) {
|
|
||||||
case ChromaLocation::COSITED_EVEN:
|
|
||||||
return VK_CHROMA_LOCATION_COSITED_EVEN;
|
|
||||||
case ChromaLocation::MIDPOINT:
|
|
||||||
return VK_CHROMA_LOCATION_MIDPOINT;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SamplerYcbcrModelConversion getYcbcrModelConversionFilament(VkSamplerYcbcrModelConversion model) {
|
|
||||||
switch (model) {
|
|
||||||
case VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
|
|
||||||
return SamplerYcbcrModelConversion::RGB_IDENTITY;
|
|
||||||
case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
|
|
||||||
return SamplerYcbcrModelConversion::YCBCR_IDENTITY;
|
|
||||||
case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
|
|
||||||
return SamplerYcbcrModelConversion::YCBCR_709;
|
|
||||||
case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
|
|
||||||
return SamplerYcbcrModelConversion::YCBCR_601;
|
|
||||||
case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
|
|
||||||
return SamplerYcbcrModelConversion::YCBCR_2020;
|
|
||||||
default:
|
|
||||||
assert_invariant(false && "Unknown data type, conversion is not supported.");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SamplerYcbcrRange getYcbcrRangeFilament(VkSamplerYcbcrRange range) {
|
|
||||||
switch (range) {
|
|
||||||
case VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
|
|
||||||
return SamplerYcbcrRange::ITU_FULL;
|
|
||||||
case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
|
|
||||||
return SamplerYcbcrRange::ITU_NARROW;
|
|
||||||
default:
|
|
||||||
assert_invariant(false && "Unknown data type, conversion is not supported.");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ChromaLocation getChromaLocationFilament(VkChromaLocation loc) {
|
|
||||||
switch (loc) {
|
|
||||||
case VK_CHROMA_LOCATION_COSITED_EVEN:
|
|
||||||
return ChromaLocation::COSITED_EVEN;
|
|
||||||
case VK_CHROMA_LOCATION_MIDPOINT:
|
|
||||||
return ChromaLocation::MIDPOINT;
|
|
||||||
default:
|
|
||||||
assert_invariant(false && "Unknown data type, conversion is not supported.");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureSwizzle getSwizzleFilament(VkComponentSwizzle c, uint8_t rgbaIndex) {
|
|
||||||
switch (c) {
|
|
||||||
case VK_COMPONENT_SWIZZLE_ZERO:
|
|
||||||
return TextureSwizzle::SUBSTITUTE_ZERO;
|
|
||||||
case VK_COMPONENT_SWIZZLE_ONE:
|
|
||||||
return TextureSwizzle::SUBSTITUTE_ONE;
|
|
||||||
case VK_COMPONENT_SWIZZLE_IDENTITY:
|
|
||||||
return (TextureSwizzle) (((uint8_t) TextureSwizzle::CHANNEL_0) + rgbaIndex);
|
|
||||||
case VK_COMPONENT_SWIZZLE_R:
|
|
||||||
return TextureSwizzle::CHANNEL_0;
|
|
||||||
case VK_COMPONENT_SWIZZLE_G:
|
|
||||||
return TextureSwizzle::CHANNEL_1;
|
|
||||||
case VK_COMPONENT_SWIZZLE_B:
|
|
||||||
return TextureSwizzle::CHANNEL_2;
|
|
||||||
case VK_COMPONENT_SWIZZLE_A:
|
|
||||||
return TextureSwizzle::CHANNEL_3;
|
|
||||||
default:
|
|
||||||
assert_invariant(false && "Unknown data type, conversion is not supported.");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend::fvkutils
|
} // namespace filament::backend::fvkutils
|
||||||
|
|||||||
@@ -56,25 +56,6 @@ uint32_t getComponentCount(VkFormat format);
|
|||||||
VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]);
|
VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]);
|
||||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
||||||
|
|
||||||
// Needed by the Platform for external sampler creation
|
|
||||||
VkFilter getFilter(SamplerMinFilter filter);
|
|
||||||
VkFilter getFilter(SamplerMagFilter filter);
|
|
||||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter);
|
|
||||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode);
|
|
||||||
VkBool32 getCompareEnable(SamplerCompareMode mode);
|
|
||||||
float getMaxLod(SamplerMinFilter filter);
|
|
||||||
|
|
||||||
// Ycbcr related functions
|
|
||||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(SamplerYcbcrModelConversion model);
|
|
||||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range);
|
|
||||||
VkChromaLocation getChromaLocation(ChromaLocation loc);
|
|
||||||
|
|
||||||
// Ycbcr related functions
|
|
||||||
SamplerYcbcrModelConversion getYcbcrModelConversionFilament(VkSamplerYcbcrModelConversion model);
|
|
||||||
SamplerYcbcrRange getYcbcrRangeFilament(VkSamplerYcbcrRange range);
|
|
||||||
ChromaLocation getChromaLocationFilament(VkChromaLocation loc);
|
|
||||||
TextureSwizzle getSwizzleFilament(VkComponentSwizzle c, uint8_t rgbaIndex);
|
|
||||||
|
|
||||||
inline VkImageViewType getViewType(SamplerType target) {
|
inline VkImageViewType getViewType(SamplerType target) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
|||||||
@@ -348,10 +348,6 @@ using SamplerBitmask = utils::bitset64;
|
|||||||
// general.
|
// general.
|
||||||
using InputAttachmentBitmask = utils::bitset64;
|
using InputAttachmentBitmask = utils::bitset64;
|
||||||
|
|
||||||
constexpr uint8_t MAX_DESCRIPTOR_SET_BITMASK_BITS =
|
|
||||||
std::max(std::max(sizeof(UniformBufferBitmask), sizeof(SamplerBitmask)),
|
|
||||||
sizeof(InputAttachmentBitmask)) * 8;
|
|
||||||
|
|
||||||
template<typename Bitmask>
|
template<typename Bitmask>
|
||||||
static constexpr uint8_t getVertexStageShift() noexcept {
|
static constexpr uint8_t getVertexStageShift() noexcept {
|
||||||
// We assume the bottom half of bits are for vertex stages.
|
// We assume the bottom half of bits are for vertex stages.
|
||||||
|
|||||||
@@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WebGPUHandles.h"
|
|
||||||
|
|
||||||
#include "WebGPUConstants.h"
|
|
||||||
|
|
||||||
#include "DriverBase.h"
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/Program.h>
|
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr std::string_view toString(ShaderStage stage) {
|
|
||||||
switch (stage) {
|
|
||||||
case ShaderStage::VERTEX:
|
|
||||||
return "vertex";
|
|
||||||
case ShaderStage::FRAGMENT:
|
|
||||||
return "fragment";
|
|
||||||
case ShaderStage::COMPUTE:
|
|
||||||
return "compute";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] wgpu::ShaderModule createShaderModule(wgpu::Device& device, const char* programName,
|
|
||||||
std::array<utils::FixedCapacityVector<uint8_t>, Program::SHADER_TYPE_COUNT> const&
|
|
||||||
shaderSource,
|
|
||||||
ShaderStage stage) {
|
|
||||||
utils::FixedCapacityVector<uint8_t> const& sourceBytes =
|
|
||||||
shaderSource[static_cast<size_t>(stage)];
|
|
||||||
if (sourceBytes.empty()) {
|
|
||||||
return nullptr;// nothing to compile, the shader was not provided
|
|
||||||
}
|
|
||||||
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
|
|
||||||
wgslDescriptor.code = wgpu::StringView(reinterpret_cast<const char*>(sourceBytes.data()));
|
|
||||||
std::stringstream labelStream;
|
|
||||||
labelStream << programName << " " << toString(stage) << " shader";
|
|
||||||
auto label = labelStream.str();
|
|
||||||
wgpu::ShaderModuleDescriptor descriptor{
|
|
||||||
.nextInChain = &wgslDescriptor,
|
|
||||||
.label = label.data()
|
|
||||||
};
|
|
||||||
wgpu::ShaderModule module = device.CreateShaderModule(&descriptor);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(module != nullptr) << "Failed to create " << descriptor.label;
|
|
||||||
module.GetCompilationInfo(wgpu::CallbackMode::AllowSpontaneous,
|
|
||||||
[&descriptor](auto const& status, wgpu::CompilationInfo const* info) {
|
|
||||||
switch (status) {
|
|
||||||
case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
|
|
||||||
FWGPU_LOGW << "Shader compilation info callback cancelled for "
|
|
||||||
<< descriptor.label << "?" << utils::io::endl;
|
|
||||||
return;
|
|
||||||
case wgpu::CompilationInfoRequestStatus::Success:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (info != nullptr) {
|
|
||||||
std::stringstream errorStream;
|
|
||||||
int errorCount = 0;
|
|
||||||
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) {
|
|
||||||
wgpu::CompilationMessage const& message = info->messages[msgIndex];
|
|
||||||
switch (message.type) {
|
|
||||||
case wgpu::CompilationMessageType::Info:
|
|
||||||
FWGPU_LOGI << descriptor.label << ": " << message.message
|
|
||||||
<< " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << utils::io::endl;
|
|
||||||
break;
|
|
||||||
case wgpu::CompilationMessageType::Warning:
|
|
||||||
FWGPU_LOGW << "Warning compiling " << descriptor.label << ": "
|
|
||||||
<< message.message << " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << utils::io::endl;
|
|
||||||
break;
|
|
||||||
case wgpu::CompilationMessageType::Error:
|
|
||||||
errorCount++;
|
|
||||||
errorStream << "Error " << errorCount << " : "
|
|
||||||
<< std::string_view(message.message)
|
|
||||||
<< " line#:" << message.lineNum
|
|
||||||
<< " linePos:" << message.linePos
|
|
||||||
<< " offset:" << message.offset
|
|
||||||
<< " length:" << message.length << "\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
|
|
||||||
<< errorCount << " error(s) compiling " << descriptor.label << ":\n"
|
|
||||||
<< errorStream.str();
|
|
||||||
}
|
|
||||||
FWGPU_LOGD << descriptor.label << " compiled successfully" << utils::io::endl;
|
|
||||||
});
|
|
||||||
return module;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<wgpu::ConstantEntry> convertConstants(
|
|
||||||
utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const&
|
|
||||||
constantsInfo) {
|
|
||||||
std::vector<wgpu::ConstantEntry> constants(constantsInfo.size());
|
|
||||||
for (size_t i = 0; i < constantsInfo.size(); i++) {
|
|
||||||
filament::backend::Program::SpecializationConstant const& specConstant = constantsInfo[i];
|
|
||||||
wgpu::ConstantEntry& constantEntry = constants[i];
|
|
||||||
constantEntry.key = wgpu::StringView(std::to_string(specConstant.id));
|
|
||||||
if (auto* v = std::get_if<int32_t>(&specConstant.value)) {
|
|
||||||
constantEntry.value = static_cast<double>(*v);
|
|
||||||
} else if (auto* f = std::get_if<float>(&specConstant.value)) {
|
|
||||||
constantEntry.value = static_cast<double>(*f);
|
|
||||||
} else if (auto* b = std::get_if<bool>(&specConstant.value)) {
|
|
||||||
constantEntry.value = *b ? 0.0 : 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
}// namespace
|
|
||||||
|
|
||||||
WGPUProgram::WGPUProgram(wgpu::Device& device, Program& program)
|
|
||||||
: HwProgram(program.getName()),
|
|
||||||
vertexShaderModule(createShaderModule(device, name.c_str_safe(), program.getShadersSource(),
|
|
||||||
ShaderStage::VERTEX)),
|
|
||||||
fragmentShaderModule(createShaderModule(device, name.c_str_safe(), program.getShadersSource(),
|
|
||||||
ShaderStage::FRAGMENT)),
|
|
||||||
computeShaderModule(createShaderModule(device, name.c_str_safe(), program.getShadersSource(),
|
|
||||||
ShaderStage::COMPUTE)),
|
|
||||||
constants(convertConstants(program.getSpecializationConstants())) {}
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
|
||||||
|
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
// FWGPU is short for Filament WebGPU
|
|
||||||
|
|
||||||
// turn on runtime validation, namely for debugging, that would normally not run (for release)
|
|
||||||
#define FWGPU_DEBUG_VALIDATION 0x00000001
|
|
||||||
// print/log system component details to the console, e.g. about the
|
|
||||||
// instance, surface, adapter, device, etc.
|
|
||||||
#define FWGPU_PRINT_SYSTEM 0x00000002
|
|
||||||
|
|
||||||
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
|
|
||||||
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
|
|
||||||
// order of calls).
|
|
||||||
#define FWGPU_DEBUG_FORCE_LOG_TO_I 0x00000004
|
|
||||||
|
|
||||||
// Useful default combinations
|
|
||||||
#define FWGPU_DEBUG_EVERYTHING 0xFFFFFFFF
|
|
||||||
|
|
||||||
#if defined(FILAMENT_BACKEND_DEBUG_FLAG)
|
|
||||||
#define FWGPU_DEBUG_FORWARDED_FLAG (FILAMENT_BACKEND_DEBUG_FLAG & FWGPU_DEBUG_EVERYTHING)
|
|
||||||
#else
|
|
||||||
#define FWGPU_DEBUG_FORWARDED_FLAG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define FWGPU_DEBUG_FLAGS FWGPU_DEBUG_FORWARDED_FLAG
|
|
||||||
#else
|
|
||||||
#define FWGPU_DEBUG_FLAGS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FWGPU_ENABLED(flags) (((FWGPU_DEBUG_FLAGS) & (flags)) == (flags))
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_DEBUG_FORCE_LOG_TO_I)
|
|
||||||
#define FWGPU_LOGI (utils::slog.i)
|
|
||||||
#define FWGPU_LOGD FWGPU_LOGI
|
|
||||||
#define FWGPU_LOGE FWGPU_LOGI
|
|
||||||
#define FWGPU_LOGW FWGPU_LOGI
|
|
||||||
#else
|
|
||||||
#define FWGPU_LOGE (utils::slog.e)
|
|
||||||
#define FWGPU_LOGW (utils::slog.w)
|
|
||||||
#define FWGPU_LOGD (utils::slog.d)
|
|
||||||
#define FWGPU_LOGI (utils::slog.i)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
|
||||||
@@ -14,230 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "webgpu/WebGPUDriver.h"
|
|
||||||
|
|
||||||
#include "WebGPUSwapChain.h"
|
|
||||||
#include "webgpu/WebGPUConstants.h"
|
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
|
||||||
|
|
||||||
#include "CommandStreamDispatcher.h"
|
|
||||||
#include "DriverBase.h"
|
|
||||||
#include "private/backend/Dispatcher.h"
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
#include <math/mat3.h>
|
#include "webgpu/WebGPUDriver.h"
|
||||||
#include <utils/CString.h>
|
#include "CommandStreamDispatcher.h"
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <dawn/webgpu_cpp_print.h>
|
#include <stdint.h>
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string_view>
|
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
namespace {
|
Driver* WebGPUDriver::create() {
|
||||||
|
return new WebGPUDriver();
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printInstanceDetails(wgpu::Instance const& instance) {
|
|
||||||
wgpu::SupportedWGSLLanguageFeatures supportedWGSLLanguageFeatures{};
|
|
||||||
if (!instance.GetWGSLLanguageFeatures(&supportedWGSLLanguageFeatures)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU instance supported WGSL language features"
|
|
||||||
<< utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU instance supported WGSL language features ("
|
|
||||||
<< supportedWGSLLanguageFeatures.featureCount << "):" << utils::io::endl;
|
|
||||||
if (supportedWGSLLanguageFeatures.featureCount > 0 &&
|
|
||||||
supportedWGSLLanguageFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedWGSLLanguageFeatures.features,
|
|
||||||
supportedWGSLLanguageFeatures.features +
|
|
||||||
supportedWGSLLanguageFeatures.featureCount,
|
|
||||||
[](wgpu::WGSLLanguageFeatureName const featureName) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << featureName;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printLimit(std::string_view name, const std::variant<uint32_t, uint64_t> value) {
|
|
||||||
FWGPU_LOGI << " " << name.data() << ": ";
|
|
||||||
bool undefined = true;
|
|
||||||
if (std::holds_alternative<uint32_t>(value)) {
|
|
||||||
if (std::get<uint32_t>(value) != WGPU_LIMIT_U32_UNDEFINED) {
|
|
||||||
undefined = false;
|
|
||||||
FWGPU_LOGI << std::get<uint32_t>(value);
|
|
||||||
}
|
|
||||||
} else if (std::holds_alternative<uint64_t>(value)) {
|
|
||||||
if (std::get<uint64_t>(value) != WGPU_LIMIT_U64_UNDEFINED) {
|
|
||||||
undefined = false;
|
|
||||||
FWGPU_LOGI << std::get<uint64_t>(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (undefined) {
|
|
||||||
FWGPU_LOGI << "UNDEFINED";
|
|
||||||
}
|
|
||||||
FWGPU_LOGI << utils::io::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printLimits(wgpu::Limits const& limits) {
|
|
||||||
printLimit("maxTextureDimension1D", limits.maxTextureDimension1D);
|
|
||||||
printLimit("maxTextureDimension2D", limits.maxTextureDimension2D);
|
|
||||||
printLimit("maxTextureDimension3D", limits.maxTextureDimension3D);
|
|
||||||
printLimit("maxTextureArrayLayers", limits.maxTextureArrayLayers);
|
|
||||||
printLimit("maxBindGroups", limits.maxBindGroups);
|
|
||||||
printLimit("maxBindGroupsPlusVertexBuffers", limits.maxBindGroupsPlusVertexBuffers);
|
|
||||||
printLimit("maxBindingsPerBindGroup", limits.maxBindingsPerBindGroup);
|
|
||||||
printLimit("maxDynamicUniformBuffersPerPipelineLayout",
|
|
||||||
limits.maxDynamicUniformBuffersPerPipelineLayout);
|
|
||||||
printLimit("maxDynamicStorageBuffersPerPipelineLayout",
|
|
||||||
limits.maxDynamicStorageBuffersPerPipelineLayout);
|
|
||||||
printLimit("maxSampledTexturesPerShaderStage", limits.maxSampledTexturesPerShaderStage);
|
|
||||||
printLimit("maxSamplersPerShaderStage", limits.maxSamplersPerShaderStage);
|
|
||||||
printLimit("maxStorageBuffersPerShaderStage", limits.maxStorageBuffersPerShaderStage);
|
|
||||||
printLimit("maxStorageTexturesPerShaderStage", limits.maxStorageTexturesPerShaderStage);
|
|
||||||
printLimit("maxUniformBuffersPerShaderStage", limits.maxUniformBuffersPerShaderStage);
|
|
||||||
printLimit("maxUniformBufferBindingSize", limits.maxUniformBufferBindingSize);
|
|
||||||
printLimit("maxStorageBufferBindingSize", limits.maxStorageBufferBindingSize);
|
|
||||||
printLimit("minUniformBufferOffsetAlignment", limits.minUniformBufferOffsetAlignment);
|
|
||||||
printLimit("minStorageBufferOffsetAlignment", limits.minStorageBufferOffsetAlignment);
|
|
||||||
printLimit("maxVertexBuffers", limits.maxVertexBuffers);
|
|
||||||
printLimit("maxBufferSize", limits.maxBufferSize);
|
|
||||||
printLimit("maxVertexAttributes", limits.maxVertexAttributes);
|
|
||||||
printLimit("maxVertexBufferArrayStride", limits.maxVertexBufferArrayStride);
|
|
||||||
printLimit("maxInterStageShaderVariables", limits.maxInterStageShaderVariables);
|
|
||||||
printLimit("maxColorAttachments", limits.maxColorAttachments);
|
|
||||||
printLimit("maxColorAttachmentBytesPerSample", limits.maxColorAttachmentBytesPerSample);
|
|
||||||
printLimit("maxComputeWorkgroupStorageSize", limits.maxComputeWorkgroupStorageSize);
|
|
||||||
printLimit("maxComputeInvocationsPerWorkgroup", limits.maxComputeInvocationsPerWorkgroup);
|
|
||||||
printLimit("maxComputeWorkgroupSizeX", limits.maxComputeWorkgroupSizeX);
|
|
||||||
printLimit("maxComputeWorkgroupSizeY", limits.maxComputeWorkgroupSizeY);
|
|
||||||
printLimit("maxComputeWorkgroupSizeZ", limits.maxComputeWorkgroupSizeZ);
|
|
||||||
printLimit("maxComputeWorkgroupsPerDimension", limits.maxComputeWorkgroupsPerDimension);
|
|
||||||
printLimit("maxStorageBuffersInVertexStage", limits.maxStorageBuffersInVertexStage);
|
|
||||||
printLimit("maxStorageTexturesInVertexStage", limits.maxStorageTexturesInVertexStage);
|
|
||||||
printLimit("maxStorageBuffersInFragmentStage", limits.maxStorageBuffersInFragmentStage);
|
|
||||||
printLimit("maxStorageTexturesInFragmentStage", limits.maxStorageTexturesInFragmentStage);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printAdapterDetails(wgpu::Adapter const& adapter) {
|
|
||||||
wgpu::DawnAdapterPropertiesPowerPreference powerPreferenceProperties{};
|
|
||||||
wgpu::AdapterInfo adapterInfo{};
|
|
||||||
adapterInfo.nextInChain = &powerPreferenceProperties;
|
|
||||||
if (!adapter.GetInfo(&adapterInfo)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU adapter info" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
std::stringstream backendTypeStream{};
|
|
||||||
backendTypeStream << adapterInfo.backendType;
|
|
||||||
std::stringstream adapterTypeStream{};
|
|
||||||
adapterTypeStream << adapterInfo.adapterType;
|
|
||||||
std::stringstream powerPreferenceStream{};
|
|
||||||
powerPreferenceStream << powerPreferenceProperties.powerPreference;
|
|
||||||
FWGPU_LOGI << "WebGPU adapter info:" << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " vendor: " << adapterInfo.vendor.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " architecture: " << adapterInfo.architecture.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " device: " << adapterInfo.device.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " description: " << adapterInfo.description.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " backend type: " << backendTypeStream.str().data() << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " adapter type: " << adapterTypeStream.str().data() << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " device ID: " << adapterInfo.deviceID << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " vendor ID: " << adapterInfo.vendorID << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " subgroup min size: " << adapterInfo.subgroupMinSize << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " subgroup max size: " << adapterInfo.subgroupMaxSize << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " power preference: " << powerPreferenceStream.str() << utils::io::endl;
|
|
||||||
}
|
|
||||||
wgpu::SupportedFeatures supportedFeatures{};
|
|
||||||
adapter.GetFeatures(&supportedFeatures);
|
|
||||||
FWGPU_LOGI << "WebGPU adapter supported features (" << supportedFeatures.featureCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedFeatures.features,
|
|
||||||
supportedFeatures.features + supportedFeatures.featureCount,
|
|
||||||
[](wgpu::FeatureName const name) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << name;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wgpu::Limits supportedLimits{};
|
|
||||||
if (!adapter.GetLimits(&supportedLimits)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU adapter supported limits" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU adapter supported limits:" << utils::io::endl;
|
|
||||||
printLimits(supportedLimits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printDeviceDetails(wgpu::Device const& device) {
|
|
||||||
wgpu::SupportedFeatures supportedFeatures{};
|
|
||||||
device.GetFeatures(&supportedFeatures);
|
|
||||||
FWGPU_LOGI << "WebGPU device supported features (" << supportedFeatures.featureCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedFeatures.features,
|
|
||||||
supportedFeatures.features + supportedFeatures.featureCount,
|
|
||||||
[](wgpu::FeatureName const name) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << name;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wgpu::Limits supportedLimits{};
|
|
||||||
if (!device.GetLimits(&supportedLimits)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU supported device limits" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU device supported limits:" << utils::io::endl;
|
|
||||||
printLimits(supportedLimits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}// namespace
|
|
||||||
|
|
||||||
Driver* WebGPUDriver::create(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept {
|
|
||||||
constexpr size_t defaultSize = FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
|
||||||
Platform::DriverConfig validConfig {driverConfig};
|
|
||||||
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
|
||||||
return new WebGPUDriver(platform, validConfig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept
|
WebGPUDriver::WebGPUDriver() noexcept = default;
|
||||||
: mPlatform(platform),
|
|
||||||
mHandleAllocator("Handles",
|
|
||||||
driverConfig.handleArenaSize,
|
|
||||||
driverConfig.disableHandleUseAfterFreeCheck,
|
|
||||||
driverConfig.disableHeapHandleTags) {
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printInstanceDetails(mPlatform.getInstance());
|
|
||||||
#endif
|
|
||||||
mAdapter = mPlatform.requestAdapter(nullptr);
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printAdapterDetails(mAdapter);
|
|
||||||
#endif
|
|
||||||
mDevice = mPlatform.requestDevice(mAdapter);
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printDeviceDetails(mDevice);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
||||||
|
|
||||||
@@ -265,7 +56,6 @@ void WebGPUDriver::terminate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::tick(int) {
|
void WebGPUDriver::tick(int) {
|
||||||
mDevice.Tick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::beginFrame(int64_t monotonic_clock_ns,
|
void WebGPUDriver::beginFrame(int64_t monotonic_clock_ns,
|
||||||
@@ -295,27 +85,15 @@ void WebGPUDriver::finish(int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||||
if (rph) {
|
|
||||||
destructHandle<WGPURenderPrimitive>(rph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
void WebGPUDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
||||||
if (vbih) {
|
|
||||||
destructHandle<WGPUVertexBufferInfo>(vbih);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
void WebGPUDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
||||||
if (vbh) {
|
|
||||||
destructHandle<WGPUVertexBuffer>(vbh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
void WebGPUDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
||||||
if (ibh) {
|
|
||||||
destructHandle<WGPUIndexBuffer>(ibh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
void WebGPUDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||||
@@ -325,19 +103,12 @@ void WebGPUDriver::destroyTexture(Handle<HwTexture> th) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyProgram(Handle<HwProgram> ph) {
|
void WebGPUDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||||
if (ph) {
|
|
||||||
destructHandle<WGPUProgram>(ph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
void WebGPUDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
void WebGPUDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
||||||
if (sch) {
|
|
||||||
destructHandle<WebGPUSwapChain>(sch);
|
|
||||||
}
|
|
||||||
mSwapChain = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyStream(Handle<HwStream> sh) {
|
void WebGPUDriver::destroyStream(Handle<HwStream> sh) {
|
||||||
@@ -347,193 +118,11 @@ void WebGPUDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh) {
|
void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh) {
|
||||||
if (tqh) {
|
|
||||||
destructHandle<WebGPUDescriptorSetLayout>(tqh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
|
|
||||||
return allocHandle<WebGPUSwapChain>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainHeadlessS() noexcept {
|
|
||||||
return Handle<HwSwapChain>((Handle<HwSwapChain>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
|
||||||
return allocHandle<WGPUTexture>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
|
||||||
return allocHandle<WGPUProgram>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwFence> WebGPUDriver::createFenceS() noexcept {
|
|
||||||
return Handle<HwFence>((Handle<HwFence>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTimerQuery> WebGPUDriver::createTimerQueryS() noexcept {
|
|
||||||
return Handle<HwTimerQuery>((Handle<HwTimerQuery>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
|
||||||
return allocHandle<HwIndexBuffer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
|
||||||
return allocHandle<WGPUBufferObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createRenderTargetS() noexcept {
|
|
||||||
return allocHandle<WGPURenderTarget>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwVertexBuffer> WebGPUDriver::createVertexBufferS() noexcept {
|
|
||||||
return allocHandle<WGPUVertexBuffer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
|
|
||||||
return Handle<HwDescriptorSet>((Handle<HwDescriptorSet>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
|
|
||||||
return allocHandle<WGPURenderPrimitive>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
|
||||||
return allocHandle<WGPUVertexBufferInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
|
||||||
return allocHandle<WGPURenderTarget>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcept {
|
|
||||||
return allocHandle<WebGPUDescriptorSetLayout>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
|
||||||
mNativeWindow = nativeWindow;
|
|
||||||
assert_invariant(!mSwapChain);
|
|
||||||
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
|
|
||||||
|
|
||||||
mQueue = mDevice.GetQueue();
|
|
||||||
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
|
||||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
|
||||||
mDevice, flags);
|
|
||||||
assert_invariant(mSwapChain);
|
|
||||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
|
||||||
"background components have been instantiated/selected, such as surface/screen, "
|
|
||||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
|
||||||
<< utils::io::endl;
|
|
||||||
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
|
||||||
FWGPU_LOGI << "If the FILAMENT_BACKEND_DEBUG_FLAG variable were set with the " << utils::io::hex
|
|
||||||
<< FWGPU_PRINT_SYSTEM << utils::io::dec
|
|
||||||
<< " bit flag on during build time the application would print system details "
|
|
||||||
"about the selected graphics device, surface, etc. To see this try "
|
|
||||||
"rebuilding Filament with that flag, e.g. ./build.sh -x "
|
|
||||||
<< FWGPU_PRINT_SYSTEM << " ..." << utils::io::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
|
||||||
uint32_t height, uint64_t flags) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
|
||||||
uint8_t attributeCount, AttributeArray attributes) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
|
||||||
Handle<HwVertexBufferInfo> vbih) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
|
||||||
uint32_t indexCount, BufferUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
|
||||||
BufferObjectBinding bindingType, BufferUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
|
||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
|
||||||
TextureUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
|
||||||
uint8_t baseLevel, uint8_t levelCount) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
|
||||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
|
||||||
backend::TextureSwizzle a) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
Platform::ExternalImageHandleRef externalImage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
void* externalImage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
void* image, uint32_t plane) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
|
||||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
|
||||||
uint32_t depth, TextureUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
|
||||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
|
||||||
constructHandle<WGPUProgram>(ph, mDevice, program);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
|
|
||||||
assert_invariant(!mDefaultRenderTarget);
|
|
||||||
mDefaultRenderTarget = constructHandle<WGPURenderTarget>(rth);
|
|
||||||
assert_invariant(mDefaultRenderTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
|
||||||
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
|
||||||
TargetBufferInfo depth, TargetBufferInfo stencil) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
|
||||||
backend::DescriptorSetLayout&& info) {
|
|
||||||
constructHandle<WebGPUDescriptorSetLayout>(dslh, std::move(info), mDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
|
||||||
Handle<HwDescriptorSetLayout> dslh) {}
|
|
||||||
|
|
||||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -651,14 +240,6 @@ size_t WebGPUDriver::getMaxUniformBufferSize() {
|
|||||||
return 16384u;
|
return 16384u;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WebGPUDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
return 2048u;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
|
||||||
return 256u;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
@@ -679,10 +260,6 @@ void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
|||||||
|
|
||||||
void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||||
Handle<HwBufferObject> boh) {
|
Handle<HwBufferObject> boh) {
|
||||||
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
|
||||||
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
|
||||||
assert_invariant(index < vertexBuffer->buffers.size());
|
|
||||||
vertexBuffer->setBuffer(bufferObject, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
||||||
@@ -715,71 +292,18 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
||||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
|
||||||
.label = "command_encoder"
|
|
||||||
};
|
|
||||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
|
||||||
assert_invariant(mCommandEncoder);
|
|
||||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
|
||||||
static float red = 1.0f;
|
|
||||||
if (red - 0.01 > 0) {
|
|
||||||
red -= 0.01;
|
|
||||||
} else {
|
|
||||||
red = 1.0f;
|
|
||||||
}
|
|
||||||
assert_invariant(mTextureView);
|
|
||||||
wgpu::RenderPassColorAttachment renderPassColorAttachment = {
|
|
||||||
.view = mTextureView,
|
|
||||||
// TODO: remove this code once WebGPU Pipeline is implemented with render targets, pipeline and buffers.
|
|
||||||
.depthSlice = wgpu::kDepthSliceUndefined,
|
|
||||||
.loadOp = wgpu::LoadOp::Clear,
|
|
||||||
.storeOp = wgpu::StoreOp::Store,
|
|
||||||
.clearValue = wgpu::Color{red, 0 , 0 , 1},
|
|
||||||
};
|
|
||||||
|
|
||||||
wgpu::RenderPassDescriptor renderPassDescriptor = {
|
|
||||||
.colorAttachmentCount = 1,
|
|
||||||
.colorAttachments = &renderPassColorAttachment,
|
|
||||||
.depthStencilAttachment = nullptr,
|
|
||||||
.timestampWrites = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
|
||||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
|
||||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::endRenderPass(int) {
|
void WebGPUDriver::endRenderPass(int) {
|
||||||
mRenderPassEncoder.End();
|
|
||||||
mRenderPassEncoder = nullptr;
|
|
||||||
wgpu::CommandBufferDescriptor commandBufferDescriptor {
|
|
||||||
.label = "command_buffer",
|
|
||||||
};
|
|
||||||
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
|
||||||
assert_invariant(mCommandBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::nextSubpass(int) {
|
void WebGPUDriver::nextSubpass(int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain> readSch) {
|
void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain> readSch) {
|
||||||
ASSERT_PRECONDITION_NON_FATAL(drawSch == readSch,
|
|
||||||
"WebGPU driver does not support distinct draw/read swap chains.");
|
|
||||||
auto* swapChain = handleCast<WebGPUSwapChain>(drawSch);
|
|
||||||
mSwapChain = swapChain;
|
|
||||||
assert_invariant(mSwapChain);
|
|
||||||
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
|
||||||
mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize);
|
|
||||||
assert_invariant(mTextureView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
||||||
mCommandEncoder = nullptr;
|
|
||||||
mQueue.Submit(1, &mCommandBuffer);
|
|
||||||
mCommandBuffer = nullptr;
|
|
||||||
mTextureView = nullptr;
|
|
||||||
assert_invariant(mSwapChain);
|
|
||||||
mSwapChain->present();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
void WebGPUDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||||
@@ -807,7 +331,7 @@ void WebGPUDriver::readPixels(Handle<HwRenderTarget> src,
|
|||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::readBufferSubData(Handle<HwBufferObject> boh,
|
void WebGPUDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
||||||
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
|
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
@@ -859,22 +383,22 @@ void WebGPUDriver::resetState(int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateDescriptorSetBuffer(
|
void WebGPUDriver::updateDescriptorSetBuffer(
|
||||||
Handle<HwDescriptorSet> dsh,
|
backend::DescriptorSetHandle dsh,
|
||||||
backend::descriptor_binding_t binding,
|
backend::descriptor_binding_t binding,
|
||||||
Handle<HwBufferObject> boh,
|
backend::BufferObjectHandle boh,
|
||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
uint32_t size) {
|
uint32_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateDescriptorSetTexture(
|
void WebGPUDriver::updateDescriptorSetTexture(
|
||||||
Handle<HwDescriptorSet> dsh,
|
backend::DescriptorSetHandle dsh,
|
||||||
backend::descriptor_binding_t binding,
|
backend::descriptor_binding_t binding,
|
||||||
Handle<HwTexture> th,
|
backend::TextureHandle th,
|
||||||
SamplerParams params) {
|
SamplerParams params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindDescriptorSet(
|
void WebGPUDriver::bindDescriptorSet(
|
||||||
Handle<HwDescriptorSet> dsh,
|
backend::DescriptorSetHandle dsh,
|
||||||
backend::descriptor_set_t set,
|
backend::descriptor_set_t set,
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,62 +17,31 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
|
|
||||||
#include "WebGPUHandles.h"
|
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
|
||||||
|
|
||||||
#include "DriverBase.h"
|
|
||||||
#include "private/backend/Dispatcher.h"
|
|
||||||
#include "private/backend/Driver.h"
|
#include "private/backend/Driver.h"
|
||||||
#include "private/backend/HandleAllocator.h"
|
#include "DriverBase.h"
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#ifndef FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB
|
|
||||||
# define FILAMENT_WEBGPU_HANDLE_ARENA_SIZE_IN_MB 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
class WebGPUSwapChain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebGPU backend (driver) implementation
|
|
||||||
*/
|
|
||||||
class WebGPUDriver final : public DriverBase {
|
class WebGPUDriver final : public DriverBase {
|
||||||
public:
|
WebGPUDriver() noexcept;
|
||||||
~WebGPUDriver() noexcept override;
|
~WebGPUDriver() noexcept override;
|
||||||
|
Dispatcher getDispatcher() const noexcept final;
|
||||||
|
|
||||||
[[nodiscard]] Dispatcher getDispatcher() const noexcept final;
|
public:
|
||||||
[[nodiscard]] static Driver* create(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept;
|
static Driver* create();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept;
|
ShaderModel getShaderModel() const noexcept final;
|
||||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
|
||||||
|
uint64_t nextFakeHandle = 1;
|
||||||
|
|
||||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
|
||||||
// handled in the WebGPUPlatform
|
|
||||||
WebGPUPlatform& mPlatform;
|
|
||||||
wgpu::Adapter mAdapter = nullptr;
|
|
||||||
wgpu::Device mDevice = nullptr;
|
|
||||||
wgpu::Queue mQueue = nullptr;
|
|
||||||
void* mNativeWindow = nullptr;
|
|
||||||
WebGPUSwapChain* mSwapChain = nullptr;
|
|
||||||
uint64_t mNextFakeHandle = 1;
|
|
||||||
wgpu::CommandEncoder mCommandEncoder = nullptr;
|
|
||||||
wgpu::TextureView mTextureView = nullptr;
|
|
||||||
wgpu::RenderPassEncoder mRenderPassEncoder = nullptr;
|
|
||||||
wgpu::CommandBuffer mCommandBuffer = nullptr;
|
|
||||||
WGPURenderTarget* mDefaultRenderTarget = nullptr;
|
|
||||||
/*
|
/*
|
||||||
* Driver interface
|
* Driver interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
friend class ConcreteDispatcher;
|
friend class ConcreteDispatcher;
|
||||||
|
|
||||||
@@ -83,39 +52,13 @@ private:
|
|||||||
RetType methodName(paramsDecl) override;
|
RetType methodName(paramsDecl) override;
|
||||||
|
|
||||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||||
RetType methodName##S() noexcept override; \
|
RetType methodName##S() noexcept override { \
|
||||||
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl);
|
return RetType((RetType::HandleId)nextFakeHandle++); } \
|
||||||
|
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl) { }
|
||||||
|
|
||||||
#include "private/backend/DriverAPI.inc"
|
#include "private/backend/DriverAPI.inc"
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory management
|
|
||||||
*/
|
|
||||||
|
|
||||||
HandleAllocatorWGPU mHandleAllocator;
|
|
||||||
|
|
||||||
template<typename D>
|
|
||||||
Handle<D> allocHandle() {
|
|
||||||
return mHandleAllocator.allocate<D>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename D, typename B, typename ... ARGS>
|
|
||||||
D* constructHandle(Handle<B>& handle, ARGS&& ... args) noexcept {
|
|
||||||
return mHandleAllocator.construct<D>(handle, std::forward<ARGS>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename D, typename B>
|
|
||||||
D* handleCast(Handle<B> handle) noexcept {
|
|
||||||
return mHandleAllocator.handle_cast<D*>(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename D, typename B>
|
|
||||||
void destructHandle(Handle<B>& handle) noexcept {
|
|
||||||
auto* p = mHandleAllocator.handle_cast<D*>(handle);
|
|
||||||
return mHandleAllocator.deallocate(handle, p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace filament::backend
|
} // namespace filament
|
||||||
|
|
||||||
#endif // TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#endif // TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WebGPUHandles.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
wgpu::Buffer createIndexBuffer(wgpu::Device const& device, uint8_t elementSize, uint32_t indexCount) {
|
|
||||||
wgpu::BufferDescriptor descriptor{ .label = "index_buffer",
|
|
||||||
.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
|
||||||
.size = elementSize * indexCount,
|
|
||||||
.mappedAtCreation = false };
|
|
||||||
return device.CreateBuffer(&descriptor);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
|
|
||||||
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
|
||||||
uint32_t indexCount)
|
|
||||||
: buffer(createIndexBuffer(device, elementSize, indexCount)) {}
|
|
||||||
|
|
||||||
|
|
||||||
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
|
|
||||||
Handle<WGPUVertexBufferInfo> vbih)
|
|
||||||
: HwVertexBuffer(vextexCount),
|
|
||||||
vbih(vbih),
|
|
||||||
buffers(bufferCount) {
|
|
||||||
wgpu::BufferDescriptor descriptor {
|
|
||||||
.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Vertex,
|
|
||||||
.size = vextexCount * bufferCount,
|
|
||||||
.mappedAtCreation = false };
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < bufferCount; ++i) {
|
|
||||||
descriptor.label = ("vertex_buffer_" + std::to_string(i)).c_str();
|
|
||||||
buffers[i] = device.CreateBuffer(&descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Empty function is a place holder for verxtex buffer updates and should be
|
|
||||||
// updated for that purpose.
|
|
||||||
void WGPUVertexBuffer::setBuffer(WGPUBufferObject* bufferObject, uint32_t index) {}
|
|
||||||
|
|
||||||
WGPUBufferObject::WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount)
|
|
||||||
: HwBufferObject(byteCount),
|
|
||||||
bufferObjectBinding(bindingType) {}
|
|
||||||
|
|
||||||
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
|
||||||
wgpu::ShaderStage retStages = wgpu::ShaderStage::None;
|
|
||||||
if (any(ShaderStageFlags::VERTEX & fFlags)) {
|
|
||||||
retStages |= wgpu::ShaderStage::Vertex;
|
|
||||||
}
|
|
||||||
if (any(ShaderStageFlags::FRAGMENT & fFlags)) {
|
|
||||||
retStages |= wgpu::ShaderStage::Fragment;
|
|
||||||
}
|
|
||||||
if (any(ShaderStageFlags::COMPUTE & fFlags)) {
|
|
||||||
retStages |= wgpu::ShaderStage::Compute;
|
|
||||||
}
|
|
||||||
return retStages;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout,
|
|
||||||
wgpu::Device const& device) {
|
|
||||||
assert_invariant(device);
|
|
||||||
|
|
||||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
|
||||||
// debugging. For now, hack an incrementing value.
|
|
||||||
static int layoutNum = 0;
|
|
||||||
|
|
||||||
uint samplerCount =
|
|
||||||
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
|
||||||
return fEntry.type == DescriptorType::SAMPLER ||
|
|
||||||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<wgpu::BindGroupLayoutEntry> wEntries;
|
|
||||||
wEntries.reserve(layout.bindings.size() + samplerCount);
|
|
||||||
|
|
||||||
for (auto fEntry: layout.bindings) {
|
|
||||||
auto& wEntry = wEntries.emplace_back();
|
|
||||||
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
|
|
||||||
wEntry.binding = fEntry.binding * 2;
|
|
||||||
|
|
||||||
switch (fEntry.type) {
|
|
||||||
// TODO Metal treats these the same. Is this fine?
|
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
|
||||||
case DescriptorType::SAMPLER: {
|
|
||||||
// Sampler binding is 2n+1 due to split.
|
|
||||||
auto& samplerEntry = wEntries.emplace_back();
|
|
||||||
samplerEntry.binding = fEntry.binding * 2 + 1;
|
|
||||||
samplerEntry.visibility = wEntry.visibility;
|
|
||||||
// We are simply hoping that undefined and defaults suffices here.
|
|
||||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::Undefined;
|
|
||||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Undefined;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DescriptorType::UNIFORM_BUFFER: {
|
|
||||||
wEntry.buffer.hasDynamicOffset =
|
|
||||||
any(fEntry.flags & DescriptorFlags::DYNAMIC_OFFSET);
|
|
||||||
wEntry.buffer.type = wgpu::BufferBindingType::Uniform;
|
|
||||||
// TODO: Ideally we fill minBindingSize
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DescriptorType::INPUT_ATTACHMENT: {
|
|
||||||
// TODO: support INPUT_ATTACHMENT. Metal does not currently.
|
|
||||||
PANIC_POSTCONDITION("Input Attachment is not supported");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DescriptorType::SHADER_STORAGE_BUFFER: {
|
|
||||||
// TODO: Vulkan does not support this, can we?
|
|
||||||
PANIC_POSTCONDITION("Shader storage is not supported");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently flags are only used to specify dynamic offset.
|
|
||||||
|
|
||||||
// UNUSED
|
|
||||||
// fEntry.count
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
|
||||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
|
||||||
// debugging. For now, hack an incrementing value.
|
|
||||||
.label{ "layout_" + std::to_string(++layoutNum) },
|
|
||||||
.entryCount = wEntries.size(),
|
|
||||||
.entries = wEntries.data()
|
|
||||||
};
|
|
||||||
// TODO Do we need to defer this until we have more info on textures and samplers??
|
|
||||||
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
|
||||||
}
|
|
||||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
|
||||||
}// namespace filament::backend
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
|
||||||
|
|
||||||
#include "DriverBase.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/Handle.h>
|
|
||||||
|
|
||||||
#include <utils/FixedCapacityVector.h>
|
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
class WGPUProgram final : public HwProgram {
|
|
||||||
public:
|
|
||||||
WGPUProgram(wgpu::Device&, Program&);
|
|
||||||
|
|
||||||
wgpu::ShaderModule vertexShaderModule = nullptr;
|
|
||||||
wgpu::ShaderModule fragmentShaderModule = nullptr;
|
|
||||||
wgpu::ShaderModule computeShaderModule = nullptr;
|
|
||||||
std::vector<wgpu::ConstantEntry> constants;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WGPUBufferObject;
|
|
||||||
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
|
|
||||||
// Update the struct when used by WebGPU driver.
|
|
||||||
struct WGPUVertexBufferInfo : public HwVertexBufferInfo {
|
|
||||||
WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
|
||||||
AttributeArray const& attributes)
|
|
||||||
: HwVertexBufferInfo(bufferCount, attributeCount),
|
|
||||||
attributes(attributes) {}
|
|
||||||
AttributeArray attributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WGPUVertexBuffer : public HwVertexBuffer {
|
|
||||||
WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
|
|
||||||
Handle<WGPUVertexBufferInfo> vbih);
|
|
||||||
|
|
||||||
void setBuffer(WGPUBufferObject *bufferObject, uint32_t index);
|
|
||||||
|
|
||||||
Handle<WGPUVertexBufferInfo> vbih;
|
|
||||||
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WGPUIndexBuffer : public HwIndexBuffer {
|
|
||||||
WGPUIndexBuffer(wgpu::Device const &device, uint8_t elementSize,
|
|
||||||
uint32_t indexCount);
|
|
||||||
|
|
||||||
wgpu::Buffer buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
|
|
||||||
// Update the struct when used by WebGPU driver.
|
|
||||||
struct WGPUBufferObject : HwBufferObject {
|
|
||||||
WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount);
|
|
||||||
|
|
||||||
wgpu::Buffer buffer;
|
|
||||||
const BufferObjectBinding bufferObjectBinding;
|
|
||||||
};
|
|
||||||
class WebGPUDescriptorSetLayout : public HwDescriptorSetLayout {
|
|
||||||
public:
|
|
||||||
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
|
||||||
~WebGPUDescriptorSetLayout();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// TODO: If this is useful elsewhere, remove it from this class
|
|
||||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
|
||||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
|
||||||
|
|
||||||
wgpu::BindGroupLayout mLayout;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
|
||||||
// Update the struct when used by WebGPU driver.
|
|
||||||
struct WGPUTexture : public HwTexture {
|
|
||||||
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
|
||||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) noexcept;
|
|
||||||
|
|
||||||
// constructors for creating texture views
|
|
||||||
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
|
||||||
|
|
||||||
wgpu::Texture texture = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
|
||||||
WGPURenderPrimitive();
|
|
||||||
|
|
||||||
void setBuffers(WGPUVertexBufferInfo const* const vbi,
|
|
||||||
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer);
|
|
||||||
|
|
||||||
WGPUVertexBuffer* vertexBuffer = nullptr;
|
|
||||||
WGPUIndexBuffer* indexBuffer = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Currently WGPURenderTarget is not used by WebGPU for useful task.
|
|
||||||
// Update the struct when used by WebGPU driver.
|
|
||||||
struct WGPURenderTarget : public HwRenderTarget {
|
|
||||||
class Attachment {
|
|
||||||
public:
|
|
||||||
friend struct WGPURenderTarget;
|
|
||||||
|
|
||||||
Attachment() = default;
|
|
||||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
|
||||||
: level(level),
|
|
||||||
layer(layer),
|
|
||||||
texture(gpuTexture->texture),
|
|
||||||
mWGPUTexture(gpuTexture) {}
|
|
||||||
|
|
||||||
uint8_t level = 0;
|
|
||||||
uint16_t layer = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
wgpu::Texture texture = nullptr;
|
|
||||||
WGPUTexture* mWGPUTexture = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
|
||||||
Attachment colorAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]);
|
|
||||||
WGPURenderTarget()
|
|
||||||
: HwRenderTarget(0, 0),
|
|
||||||
defaultRenderTarget(true) {}
|
|
||||||
|
|
||||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor* descriptor,
|
|
||||||
const RenderPassParams& params);
|
|
||||||
|
|
||||||
math::uint2 getAttachmentSize() noexcept;
|
|
||||||
|
|
||||||
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
|
||||||
uint8_t getSamples() const { return samples; }
|
|
||||||
|
|
||||||
Attachment getDrawColorAttachment(size_t index);
|
|
||||||
Attachment getReadColorAttachment(size_t index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static wgpu::LoadOp getLoadAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
|
||||||
static wgpu::LoadOp getStoreAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
|
||||||
|
|
||||||
bool defaultRenderTarget = false;
|
|
||||||
uint8_t samples = 1;
|
|
||||||
|
|
||||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
|
||||||
math::uint2 attachmentSize = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user