Compare commits
81
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69d5ac2107 | ||
|
|
c01d2c09b6 | ||
|
|
f37d8b2fc2 | ||
|
|
6397fa3fe1 | ||
|
|
37d1baf0e8 | ||
|
|
1596a5ec71 | ||
|
|
22e62b92a6 | ||
|
|
8f979dacaf | ||
|
|
e3cb67045b | ||
|
|
f4cd9f712a | ||
|
|
99b3587dd3 | ||
|
|
8e30b1bfc9 | ||
|
|
c0b1daf339 | ||
|
|
efb94da111 | ||
|
|
c538bded6f | ||
|
|
f6d9db14c3 | ||
|
|
91ce3a9375 | ||
|
|
3aeee1630a | ||
|
|
15d77ed1d7 | ||
|
|
6a64cdb059 | ||
|
|
cf0cb66b28 | ||
|
|
3a2333d709 | ||
|
|
6790a1238b | ||
|
|
fad5d57053 | ||
|
|
e95f0ed6a0 | ||
|
|
73b0be799c | ||
|
|
6de6a2123d | ||
|
|
d161ef24f5 | ||
|
|
c3ea1e45f9 | ||
|
|
c6c20df474 | ||
|
|
bbb45218ac | ||
|
|
02bdddf50e | ||
|
|
21d93ce49d | ||
|
|
cab5fc561c | ||
|
|
c780804fd6 | ||
|
|
b6d6f8f6e4 | ||
|
|
f098d08c48 | ||
|
|
5c08f34e8c | ||
|
|
a37d03101e | ||
|
|
c0819b781a | ||
|
|
d9bf68ed06 | ||
|
|
32ac10161b | ||
|
|
d073fb5342 | ||
|
|
8fe7c1ff30 | ||
|
|
3b12e54573 | ||
|
|
a1f146ebea | ||
|
|
9401d6be9e | ||
|
|
111be6ef6d | ||
|
|
bd0ca7a9bd | ||
|
|
8797f45bd0 | ||
|
|
f04a25028e | ||
|
|
bb1f58e97c | ||
|
|
189e36d539 | ||
|
|
cba819be8f | ||
|
|
41e1e7e54b | ||
|
|
d8580d93ad | ||
|
|
fef40a8c5d | ||
|
|
d299b1f00e | ||
|
|
daa2790c4e | ||
|
|
d2cb53e39d | ||
|
|
315c8d75bc | ||
|
|
c19785b72f | ||
|
|
38b3074835 | ||
|
|
929ad27606 | ||
|
|
c12bcbb21e | ||
|
|
07f07e0700 | ||
|
|
7e0181b2cf | ||
|
|
b4162eb313 | ||
|
|
a0dc7104b6 | ||
|
|
80f151ccf7 | ||
|
|
26bb99c64e | ||
|
|
1612cdb353 | ||
|
|
e75882e4d4 | ||
|
|
2e763149e7 | ||
|
|
e40a4c69a3 | ||
|
|
9a1ee1ff67 | ||
|
|
9fb692b2f6 | ||
|
|
ac7c679783 | ||
|
|
38a3c52629 | ||
|
|
29ecfd5fda | ||
|
|
f11a04722b |
@@ -8,15 +8,35 @@ on:
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: ubuntu-22.04-32core
|
||||
build-android-armv7:
|
||||
name: build-android-armv7
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: armeabi-v7a,arm64-v8a,x86_64
|
||||
build-abi: armeabi-v7a
|
||||
|
||||
build-android-armv8a:
|
||||
name: build-android-armv8a
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: arm64-v8a
|
||||
|
||||
build-android-x86_64:
|
||||
name: build-android-x86_64
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: x86_64
|
||||
|
||||
@@ -10,14 +10,14 @@ on:
|
||||
jobs:
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: filament-ios
|
||||
path: out/filament-release-ios.tgz
|
||||
|
||||
@@ -10,14 +10,14 @@ on:
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
|
||||
@@ -10,14 +10,14 @@ on:
|
||||
jobs:
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14-xlarge, ubuntu-22.04-16core]
|
||||
os: [macos-14, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: win-2019-16core
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
build-ios:
|
||||
name: build-iOS
|
||||
runs-on: macos-14-xlarge
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14-xlarge, ubuntu-22.04-32core]
|
||||
os: [macos-14, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- name: Decide Git ref
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: macos-14
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
||||
|
||||
steps:
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: macos-14
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
|
||||
|
||||
steps:
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
runs-on: macos-14
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'ios'
|
||||
|
||||
steps:
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2019-32core
|
||||
runs-on: windows-2019
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'windows'
|
||||
|
||||
steps:
|
||||
@@ -205,7 +205,6 @@ jobs:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
build\windows\build-github.bat release
|
||||
echo on
|
||||
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
|
||||
shell: cmd
|
||||
- uses: actions/github-script@v6
|
||||
|
||||
@@ -10,14 +10,14 @@ on:
|
||||
jobs:
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: ubuntu-22.04-16core
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: filament-web
|
||||
path: out/filament-release-web.tgz
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
jobs:
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2019-32core
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
shell: cmd
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: filament-windows
|
||||
path: out/filament-windows.tgz
|
||||
|
||||
@@ -7,3 +7,5 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- Add support for multi-layered render target with array textures.
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.55.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.54.2'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.55.0'
|
||||
pod 'Filament', '~> 1.54.2'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,16 +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
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.55.0
|
||||
- Add descriptor sets to describe shader resources. [⚠️ **New Material Version**]
|
||||
|
||||
## v1.54.5
|
||||
|
||||
|
||||
## v1.54.4
|
||||
|
||||
- Add support for multi-layered render target with array textures.
|
||||
|
||||
## v1.54.3
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.55.0
|
||||
VERSION_NAME=1.54.2
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
if [ `uname` == "Linux" ];then
|
||||
source `dirname $0`/../linux/ci-common.sh
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip
|
||||
unzip -q ninja-linux.zip
|
||||
elif [ `uname` == "Darwin" ];then
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
||||
unzip -q ninja-mac.zip
|
||||
@@ -12,6 +13,9 @@ fi
|
||||
chmod +x ninja
|
||||
export PATH="$PWD:$PATH"
|
||||
|
||||
# FIXME: kokoro machines have node and npm but currently they are symlinked to non-existent files
|
||||
# npm install -g typescript
|
||||
|
||||
# Install emscripten.
|
||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.15.zip > emsdk.zip
|
||||
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
||||
|
||||
@@ -115,23 +115,17 @@ cmake ..\.. ^
|
||||
-DFILAMENT_SUPPORTS_VULKAN=ON ^
|
||||
|| exit /b
|
||||
|
||||
set build_flags=-j %NUMBER_OF_PROCESSORS%
|
||||
|
||||
@echo on
|
||||
|
||||
:: we've upgraded the windows machines, so the following are no longer accurate as of 09/19/24, but
|
||||
:: keeping around the comment for record.
|
||||
|
||||
:: Attempt to fix "error C1060: compiler is out of heap space" seen on CI.
|
||||
:: Some resource libraries require significant heap space to compile, so first compile them serially.
|
||||
:: cmake --build . --target filagui --config %config% %build_flags% || exit /b
|
||||
:: cmake --build . --target uberarchive --config %config% %build_flags% || exit /b
|
||||
:: cmake --build . --target gltf-demo-resources --config %config% %build_flags% || exit /b
|
||||
:: cmake --build . --target filamentapp-resources --config %config% %build_flags% || exit /b
|
||||
:: cmake --build . --target sample-resources --config %config% %build_flags% || exit /b
|
||||
:: cmake --build . --target suzanne-resources --config %config% %build_flags% || exit /b
|
||||
@echo on
|
||||
cmake --build . --target filagui --config %config% || exit /b
|
||||
cmake --build . --target uberarchive --config %config% || exit /b
|
||||
cmake --build . --target gltf-demo-resources --config %config% || exit /b
|
||||
cmake --build . --target filamentapp-resources --config %config% || exit /b
|
||||
cmake --build . --target sample-resources --config %config% || exit /b
|
||||
cmake --build . --target suzanne-resources --config %config% || exit /b
|
||||
|
||||
cmake --build . %INSTALL% --config %config% %build_flags% -- /m || exit /b
|
||||
cmake --build . %INSTALL% --config %config% -- /m || exit /b
|
||||
@echo off
|
||||
|
||||
echo Disk info after building variant: %variant%
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -66,7 +66,6 @@ set(SRCS
|
||||
src/FrameSkipper.cpp
|
||||
src/Froxelizer.cpp
|
||||
src/Frustum.cpp
|
||||
src/HwDescriptorSetLayoutFactory.cpp
|
||||
src/HwRenderPrimitiveFactory.cpp
|
||||
src/HwVertexBufferInfoFactory.cpp
|
||||
src/IndexBuffer.cpp
|
||||
@@ -154,7 +153,6 @@ set(PRIVATE_HDRS
|
||||
src/FrameInfo.h
|
||||
src/FrameSkipper.h
|
||||
src/Froxelizer.h
|
||||
src/HwDescriptorSetLayoutFactory.h
|
||||
src/HwRenderPrimitiveFactory.h
|
||||
src/HwVertexBufferInfoFactory.h
|
||||
src/Intersections.h
|
||||
|
||||
@@ -526,8 +526,6 @@ if (APPLE AND NOT IOS)
|
||||
|
||||
add_executable(metal_utils_test test/MetalTest.mm)
|
||||
|
||||
target_compile_options(metal_utils_test PRIVATE "-fobjc-arc")
|
||||
|
||||
target_link_libraries(metal_utils_test PRIVATE
|
||||
backend
|
||||
getopt
|
||||
|
||||
@@ -242,17 +242,8 @@ struct DescriptorSetLayoutBinding {
|
||||
DescriptorType type;
|
||||
ShaderStageFlags stageFlags;
|
||||
descriptor_binding_t binding;
|
||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||
uint16_t count = 0;
|
||||
|
||||
friend inline bool operator==(
|
||||
DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.flags == rhs.flags &&
|
||||
lhs.count == rhs.count &&
|
||||
lhs.stageFlags == rhs.stageFlags;
|
||||
}
|
||||
DescriptorFlags flags;
|
||||
uint16_t count;
|
||||
};
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
|
||||
@@ -30,6 +30,10 @@ namespace filament::backend {
|
||||
|
||||
struct TargetBufferInfo {
|
||||
// note: the parameters of this constructor are not in the order of this structure's fields
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer, uint8_t baseViewIndex) noexcept
|
||||
: handle(handle), baseViewIndex(baseViewIndex), level(level), layer(layer) {
|
||||
}
|
||||
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
||||
: handle(handle), level(level), layer(layer) {
|
||||
}
|
||||
@@ -47,15 +51,14 @@ struct TargetBufferInfo {
|
||||
// texture to be used as render target
|
||||
Handle<HwTexture> handle;
|
||||
|
||||
// Starting layer index for multiview. This value is only used when the `layerCount` for the
|
||||
// render target is greater than 1.
|
||||
uint8_t baseViewIndex = 0;
|
||||
|
||||
// level to be used
|
||||
uint8_t level = 0;
|
||||
|
||||
// - For cubemap textures, this indicates the face of the cubemap. See TextureCubemapFace for
|
||||
// the face->layer mapping)
|
||||
// - For 2d array, cubemap array, and 3d textures, this indicates an index of a single layer of
|
||||
// them.
|
||||
// - For multiview textures (i.e., layerCount for the RenderTarget is greater than 1), this
|
||||
// indicates a starting layer index of the current 2d array texture for multiview.
|
||||
// For cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
|
||||
uint16_t layer = 0;
|
||||
};
|
||||
|
||||
@@ -100,7 +103,7 @@ public:
|
||||
|
||||
// this is here for backward compatibility
|
||||
MRT(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
||||
: mInfos{{ handle, level, layer }} {
|
||||
: mInfos{{ handle, level, layer, 0 }} {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -73,11 +73,10 @@ public:
|
||||
enum class Type {
|
||||
NONE = 0,
|
||||
GENERIC = 1,
|
||||
RING = 2, // deprecated
|
||||
RING = 2,
|
||||
STAGING = 3,
|
||||
DESCRIPTOR_SET = 4,
|
||||
};
|
||||
static constexpr size_t TypeCount = 4;
|
||||
static constexpr size_t TypeCount = 3;
|
||||
|
||||
static constexpr auto toIndex(Type t) {
|
||||
assert_invariant(t != Type::NONE);
|
||||
@@ -89,8 +88,6 @@ public:
|
||||
return 1;
|
||||
case Type::STAGING:
|
||||
return 2;
|
||||
case Type::DESCRIPTOR_SET:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,8 +251,6 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns,
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::RING));
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers.staging",
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::STAGING));
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers.descriptor_set",
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::DESCRIPTOR_SET));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,11 +517,6 @@ void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
}
|
||||
|
||||
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
|
||||
#if FILAMENT_METAL_DEBUG_LOG
|
||||
auto handleId = rph.getId();
|
||||
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
|
||||
utils::slog.d << program << utils::io::endl;
|
||||
#endif
|
||||
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
|
||||
}
|
||||
|
||||
@@ -657,9 +650,10 @@ void MetalDriver::createDescriptorSetLayoutR(
|
||||
[](const auto& a, const auto& b) { return a.binding < b.binding; });
|
||||
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = {\n", dslh.getId());
|
||||
for (size_t i = 0; i < info.bindings.size(); i++) {
|
||||
DEBUG_LOG(" {binding = %d, type = %s, count = %d, stage = %s, flags = %s},\n",
|
||||
DEBUG_LOG(" {binding = %d, type = %s, count = %d, stage = %s, flags = %s}",
|
||||
info.bindings[i].binding, toString(info.bindings[i].type), info.bindings[i].count,
|
||||
toString(info.bindings[i].stageFlags), toString(info.bindings[i].flags));
|
||||
DEBUG_LOG(",\n");
|
||||
}
|
||||
DEBUG_LOG("})\n");
|
||||
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
|
||||
@@ -1602,7 +1596,6 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
|
||||
<< "bindPipeline() without a valid command encoder.";
|
||||
DEBUG_LOG("bindPipeline(ps = { program = %d }))\n", ps.program.getId());
|
||||
|
||||
MetalVertexBufferInfo const* const vbi =
|
||||
handle_cast<MetalVertexBufferInfo>(ps.vertexBufferInfo);
|
||||
@@ -1794,7 +1787,7 @@ void MetalDriver::bindDescriptorSet(
|
||||
const size_t dynamicBindings = descriptorSet->layout->getDynamicOffsetCount();
|
||||
utils::FixedCapacityVector<size_t> offsetsVector(dynamicBindings, 0);
|
||||
#if FILAMENT_METAL_DEBUG_LOG == 1
|
||||
printf("[METAL DEBUG] bindDescriptorSet(dsh = %d, set = %d, offsets = [", dsh.getId(), set);
|
||||
DEBUG_LOG("bindDescriptorSet(dsh = %d, set = %d, offsets = [", dsh.getId(), set);
|
||||
for (size_t i = 0; i < dynamicBindings; i++) {
|
||||
printf("%d", offsets[i]);
|
||||
if (i < dynamicBindings - 1) {
|
||||
@@ -1803,7 +1796,7 @@ void MetalDriver::bindDescriptorSet(
|
||||
|
||||
offsetsVector[i] = offsets[i];
|
||||
}
|
||||
printf("])\n");
|
||||
DEBUG_LOG("])\n");
|
||||
#endif
|
||||
|
||||
// Bind the descriptor set.
|
||||
|
||||
@@ -511,7 +511,7 @@ struct MetalDescriptorSet : public HwDescriptorSet {
|
||||
|
||||
std::vector<std::shared_ptr<MetalExternalImage>> externalImages;
|
||||
|
||||
std::array<TrackedMetalBuffer, Program::SHADER_TYPE_COUNT> cachedBuffer = { nil };
|
||||
std::array<id<MTLBuffer>, Program::SHADER_TYPE_COUNT> cachedBuffer = { nil };
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
@@ -1345,7 +1345,7 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
||||
auto& buffer = cachedBuffer[index];
|
||||
|
||||
if (buffer) {
|
||||
return buffer.get();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Map all the texture bindings to their respective texture types.
|
||||
@@ -1368,13 +1368,9 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
||||
id<MTLArgumentEncoder> encoder =
|
||||
layout->getArgumentEncoder(context.device, stage, textureTypes);
|
||||
|
||||
{
|
||||
ScopedAllocationTimer timer("descriptor_set");
|
||||
buffer = { [context.device newBufferWithLength:encoder.encodedLength
|
||||
options:MTLResourceStorageModeShared],
|
||||
TrackedMetalBuffer::Type::DESCRIPTOR_SET };
|
||||
}
|
||||
[encoder setArgumentBuffer:buffer.get() offset:0];
|
||||
buffer = [context.device newBufferWithLength:encoder.encodedLength
|
||||
options:MTLResourceStorageModeShared];
|
||||
[encoder setArgumentBuffer:buffer offset:0];
|
||||
|
||||
for (auto const& binding : bindings) {
|
||||
if (!hasShaderType(binding.stageFlags, stage)) {
|
||||
@@ -1421,7 +1417,7 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.get();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
|
||||
@@ -434,7 +434,7 @@ public:
|
||||
|
||||
private:
|
||||
static_assert(N <= 8);
|
||||
std::array<__weak id<MTLBuffer>, N> mBuffers = { nil };
|
||||
std::array<__unsafe_unretained id<MTLBuffer>, N> mBuffers = { nil };
|
||||
std::array<NSUInteger, N> mOffsets = { 0 };
|
||||
utils::bitset8 mDirtyBuffers;
|
||||
utils::bitset8 mDirtyOffsets;
|
||||
|
||||
@@ -67,9 +67,7 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
|
||||
bool const dynamicOffset = any(entry.flags & DescriptorFlags::DYNAMIC_OFFSET);
|
||||
dynamicBuffers.set(index, dynamicOffset);
|
||||
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||
if (dynamicOffset) {
|
||||
dynamicBufferCount++;
|
||||
}
|
||||
dynamicBufferCount++;
|
||||
desc.emplace<BufferGLES2>(dynamicOffset);
|
||||
} else {
|
||||
auto const type = GLUtils::getBufferBindingType(BufferObjectBinding::UNIFORM);
|
||||
|
||||
@@ -78,12 +78,8 @@ struct GLDescriptorSet : public HwDescriptorSet {
|
||||
private:
|
||||
// a Buffer Descriptor such as SSBO or UBO with static offset
|
||||
struct Buffer {
|
||||
// Workaround: we cannot define the following as Buffer() = default because one of our
|
||||
// clients has their compiler set up where such declaration (possibly coupled with explicit)
|
||||
// will be considered a deleted constructor.
|
||||
Buffer() {}
|
||||
|
||||
explicit Buffer(GLenum target) noexcept : target(target) {}
|
||||
Buffer() = default;
|
||||
explicit Buffer(GLenum target) noexcept : target(target) { }
|
||||
GLenum target; // 4
|
||||
GLuint id = 0; // 4
|
||||
uint32_t offset = 0; // 4
|
||||
|
||||
@@ -552,14 +552,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
} else if (strstr(renderer, "AMD") ||
|
||||
strstr(renderer, "ATI")) {
|
||||
// AMD/ATI GPU
|
||||
} else if (strstr(vendor, "Mesa")) {
|
||||
// Seen on
|
||||
// [Mesa],
|
||||
// [llvmpipe (LLVM 17.0.6, 256 bits)],
|
||||
// [4.5 (Core Profile) Mesa 24.0.6-1],
|
||||
// [4.50]
|
||||
// not known which version are affected
|
||||
bugs->rebind_buffer_after_deletion = true;
|
||||
} else if (strstr(renderer, "Mozilla")) {
|
||||
bugs->disable_invalidate_framebuffer = true;
|
||||
}
|
||||
@@ -937,19 +929,15 @@ void OpenGLContext::unbindSampler(GLuint sampler) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLContext::deleteBuffer(GLuint buffer, GLenum target) noexcept {
|
||||
glDeleteBuffers(1, &buffer);
|
||||
|
||||
void OpenGLContext::deleteBuffers(GLsizei n, const GLuint* buffers, GLenum target) noexcept {
|
||||
glDeleteBuffers(n, buffers);
|
||||
// bindings of bound buffers are reset to 0
|
||||
size_t const targetIndex = getIndexForBufferTarget(target);
|
||||
auto& genericBinding = state.buffers.genericBinding[targetIndex];
|
||||
if (genericBinding == buffer) {
|
||||
genericBinding = 0;
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(bugs.rebind_buffer_after_deletion)) {
|
||||
if (genericBinding) {
|
||||
glBindBuffer(target, genericBinding);
|
||||
const size_t targetIndex = getIndexForBufferTarget(target);
|
||||
auto& genericBuffer = state.buffers.genericBinding[targetIndex];
|
||||
UTILS_NOUNROLL
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (genericBuffer == buffers[i]) {
|
||||
genericBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,13 +946,16 @@ void OpenGLContext::deleteBuffer(GLuint buffer, GLenum target) noexcept {
|
||||
(target != GL_UNIFORM_BUFFER && target != GL_TRANSFORM_FEEDBACK_BUFFER));
|
||||
|
||||
if (target == GL_UNIFORM_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER) {
|
||||
auto& indexedBinding = state.buffers.targets[targetIndex];
|
||||
UTILS_NOUNROLL
|
||||
for (auto& entry: indexedBinding.buffers) {
|
||||
if (entry.name == buffer) {
|
||||
entry.name = 0;
|
||||
entry.offset = 0;
|
||||
entry.size = 0;
|
||||
auto& indexedBuffer = state.buffers.targets[targetIndex];
|
||||
UTILS_NOUNROLL // clang generates >1 KiB of code!!
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
UTILS_NOUNROLL
|
||||
for (auto& buffer : indexedBuffer.buffers) {
|
||||
if (buffer.name == buffers[i]) {
|
||||
buffer.name = 0;
|
||||
buffer.offset = 0;
|
||||
buffer.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
inline void viewport(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept;
|
||||
inline void depthRange(GLclampf near, GLclampf far) noexcept;
|
||||
|
||||
void deleteBuffer(GLuint buffer, GLenum target) noexcept;
|
||||
void deleteBuffers(GLsizei n, const GLuint* buffers, GLenum target) noexcept;
|
||||
void deleteVertexArray(GLuint vao) noexcept;
|
||||
|
||||
void destroyWithContext(size_t index, std::function<void(OpenGLContext&)> const& closure) noexcept;
|
||||
@@ -316,15 +316,10 @@ public:
|
||||
// a glFinish. So we must delay the destruction until we know the GPU is finished.
|
||||
bool delay_fbo_destruction;
|
||||
|
||||
// Mesa sometimes clears the generic buffer binding when *another* buffer is destroyed,
|
||||
// if that other buffer is bound on an *indexed* buffer binding.
|
||||
bool rebind_buffer_after_deletion;
|
||||
|
||||
// Force feature level 0. Typically used for low end ES3 devices with significant driver
|
||||
// bugs or performance issues.
|
||||
bool force_feature_level0;
|
||||
|
||||
|
||||
} bugs = {};
|
||||
|
||||
// state getters -- as needed.
|
||||
@@ -559,9 +554,6 @@ private:
|
||||
{ bugs.delay_fbo_destruction,
|
||||
"delay_fbo_destruction",
|
||||
""},
|
||||
{ bugs.rebind_buffer_after_deletion,
|
||||
"rebind_buffer_after_deletion",
|
||||
""},
|
||||
{ bugs.force_feature_level0,
|
||||
"force_feature_level0",
|
||||
""},
|
||||
|
||||
@@ -1266,7 +1266,6 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
switch (t->target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_3D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
// this could be GL_TEXTURE_2D_MULTISAMPLE or GL_TEXTURE_2D_ARRAY
|
||||
@@ -1277,9 +1276,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
target = getCubemapTarget(binfo.layer);
|
||||
// note: cubemaps can't be multi-sampled
|
||||
break;
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
// This is an error. We have asserted in debug build.
|
||||
target = t->gl.target;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1297,7 +1294,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
|
||||
if (rt->gl.samples <= 1 ||
|
||||
(rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) {
|
||||
// On GL3.2 / GLES3.1 and above multisample is handled when creating the texture.
|
||||
// on GL3.2 / GLES3.1 and above multisample is handled when creating the texture.
|
||||
// If multisampled textures are not supported and we end-up here, things should
|
||||
// still work, albeit without MSAA.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
@@ -1321,7 +1318,6 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
case GL_TEXTURE_CUBE_MAP_ARRAY:
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
@@ -1331,7 +1327,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
if (layerCount > 1) {
|
||||
// if layerCount > 1, it means we use the multiview extension.
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, 0, binfo.layer, layerCount);
|
||||
t->gl.id, 0, binfo.baseViewIndex, layerCount);
|
||||
} else
|
||||
#endif // !defined(__EMSCRIPTEN__) && !defined(IOS)
|
||||
{
|
||||
@@ -1435,7 +1431,6 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
case GL_TEXTURE_CUBE_MAP_ARRAY:
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
@@ -1732,7 +1727,7 @@ void OpenGLDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
||||
if (ibh) {
|
||||
auto& gl = mContext;
|
||||
GLIndexBuffer const* ib = handle_cast<const GLIndexBuffer*>(ibh);
|
||||
gl.deleteBuffer(ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
|
||||
gl.deleteBuffers(1, &ib->gl.buffer, GL_ELEMENT_ARRAY_BUFFER);
|
||||
destruct(ibh, ib);
|
||||
}
|
||||
}
|
||||
@@ -1745,7 +1740,7 @@ void OpenGLDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||
if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
free(bo->gl.buffer);
|
||||
} else {
|
||||
gl.deleteBuffer(bo->gl.id, bo->gl.binding);
|
||||
gl.deleteBuffers(1, &bo->gl.id, bo->gl.binding);
|
||||
}
|
||||
destruct(boh, bo);
|
||||
}
|
||||
@@ -2914,9 +2909,6 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
GLuint const fbo = gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
|
||||
|
||||
// each render-pass starts with a disabled scissor
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
|
||||
if (gl.ext.EXT_discard_framebuffer
|
||||
&& !gl.bugs.disable_invalidate_framebuffer) {
|
||||
AttachmentArray attachments; // NOLINT
|
||||
@@ -2929,6 +2921,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
// It's important to clear the framebuffer before drawing, as it resets
|
||||
// the fb to a known state (resets fb compression and possibly other things).
|
||||
// So we use glClear instead of glInvalidateFramebuffer
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
clearWithRasterPipe(discardFlags & ~clearFlags, { 0.0f }, 0.0f, 0);
|
||||
}
|
||||
|
||||
@@ -2944,6 +2937,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
}
|
||||
|
||||
if (any(clearFlags)) {
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
clearWithRasterPipe(clearFlags,
|
||||
params.clearColor, (GLfloat)params.clearDepth, (GLint)params.clearStencil);
|
||||
}
|
||||
@@ -2962,6 +2956,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
|
||||
#ifndef NDEBUG
|
||||
// clear the discarded (but not the cleared ones) buffers in debug builds
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
clearWithRasterPipe(discardFlags & ~clearFlags,
|
||||
{ 1, 0, 0, 1 }, 1.0, 0);
|
||||
#endif
|
||||
@@ -3892,7 +3887,6 @@ void OpenGLDriver::bindDescriptorSet(
|
||||
// `offsets` data's lifetime will end when this function returns. We have to make a copy.
|
||||
// (the data is allocated inside the CommandStream)
|
||||
mBoundDescriptorSets[set].dsh = dsh;
|
||||
assert_invariant(offsets.data() != nullptr || ds->getDynamicBufferCount() == 0);
|
||||
std::copy_n(offsets.data(), ds->getDynamicBufferCount(),
|
||||
mBoundDescriptorSets[set].offsets.data());
|
||||
}
|
||||
|
||||
@@ -155,6 +155,10 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
|
||||
ext.egl.KHR_no_config_context = extensions.has("EGL_KHR_no_config_context");
|
||||
ext.egl.KHR_surfaceless_context = extensions.has("EGL_KHR_surfaceless_context");
|
||||
ext.egl.EXT_protected_content = extensions.has("EGL_EXT_protected_content");
|
||||
if (ext.egl.KHR_create_context) {
|
||||
// KHR_create_context implies KHR_surfaceless_context for ES3.x contexts
|
||||
ext.egl.KHR_surfaceless_context = true;
|
||||
}
|
||||
|
||||
eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
|
||||
eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
|
||||
|
||||
@@ -410,6 +410,7 @@ io::ostream& operator<<(io::ostream& out, const RasterState& rs) {
|
||||
io::ostream& operator<<(io::ostream& out, const TargetBufferInfo& tbi) {
|
||||
return out << "TargetBufferInfo{"
|
||||
<< "handle=" << tbi.handle
|
||||
<< ", baseViewIndex=" << tbi.baseViewIndex
|
||||
<< ", level=" << tbi.level
|
||||
<< ", layer=" << tbi.layer << "}";
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ struct VulkanCommandBuffer;
|
||||
struct VulkanAttachment {
|
||||
VulkanTexture* texture = nullptr;
|
||||
uint8_t level = 0;
|
||||
uint8_t baseViewIndex = 0;
|
||||
uint8_t layerCount = 1;
|
||||
uint16_t layer = 0;
|
||||
|
||||
|
||||
@@ -647,6 +647,7 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
colorTargets[i] = {
|
||||
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(color[i].handle),
|
||||
.level = color[i].level,
|
||||
.baseViewIndex = color[i].baseViewIndex,
|
||||
.layerCount = layerCount,
|
||||
.layer = color[i].layer,
|
||||
};
|
||||
@@ -662,6 +663,7 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
depthStencil[0] = {
|
||||
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(depth.handle),
|
||||
.level = depth.level,
|
||||
.baseViewIndex = depth.baseViewIndex,
|
||||
.layerCount = layerCount,
|
||||
.layer = depth.layer,
|
||||
};
|
||||
@@ -675,6 +677,7 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
depthStencil[1] = {
|
||||
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(stencil.handle),
|
||||
.level = stencil.level,
|
||||
.baseViewIndex = stencil.baseViewIndex,
|
||||
.layerCount = layerCount,
|
||||
.layer = stencil.layer,
|
||||
};
|
||||
@@ -746,10 +749,7 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||
backend::DescriptorSetLayout&& info) {
|
||||
VulkanDescriptorSetLayout* layout = mResourceAllocator.construct<VulkanDescriptorSetLayout>(
|
||||
dslh, info);
|
||||
|
||||
// This will create a VkDescriptorSetLayout (which is cached) for this object.
|
||||
mDescriptorSetManager.initVkLayout(layout);
|
||||
dslh, mPlatform->getDevice(), info);
|
||||
mResourceManager.acquire(layout);
|
||||
}
|
||||
|
||||
@@ -1288,12 +1288,6 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
// the non-sampling case.
|
||||
VulkanCommandBuffer& commands = mCommands.get();
|
||||
VkCommandBuffer const cmdbuffer = commands.buffer();
|
||||
|
||||
// Scissor is reset with each render pass
|
||||
// This also takes care of VUID-vkCmdDrawIndexed-None-07832.
|
||||
VkRect2D const scissor{ .offset = { 0, 0 }, .extent = extent };
|
||||
vkCmdSetScissor(cmdbuffer, 0, 1, &scissor);
|
||||
|
||||
VulkanLayout currentDepthLayout = depth.getLayout();
|
||||
|
||||
TargetBufferFlags clearVal = params.flags.clear;
|
||||
@@ -1315,6 +1309,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
|
||||
// Create the VkRenderPass or fetch it from cache.
|
||||
VulkanFboCache::RenderPassKey rpkey = {
|
||||
.initialColorLayoutMask = 0,
|
||||
.initialDepthLayout = currentDepthLayout,
|
||||
.depthFormat = depth.getFormat(),
|
||||
.clear = clearVal,
|
||||
@@ -1328,6 +1323,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
VulkanAttachment const& info = rt->getColor(i);
|
||||
if (info.texture) {
|
||||
assert_invariant(info.layerCount == renderTargetLayerCount);
|
||||
rpkey.initialColorLayoutMask |= 1 << i;
|
||||
rpkey.colorFormat[i] = info.getFormat();
|
||||
if (rpkey.samples > 1 && info.texture->samples == 1) {
|
||||
rpkey.needsResolveMask |= (1 << i);
|
||||
@@ -1359,15 +1355,9 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
|
||||
if (fbkey.samples == 1) {
|
||||
auto const& range = attachment.getSubresourceRange();
|
||||
auto tex = attachment.texture;
|
||||
if (tex->getLayout(range.baseMipLevel, range.baseArrayLayer) !=
|
||||
VulkanLayout::COLOR_ATTACHMENT &&
|
||||
!tex->transitionLayout(&commands, range, VulkanLayout::COLOR_ATTACHMENT)) {
|
||||
// If the layout transition did not emit a barrier, we do it manually here.
|
||||
tex->samplerToAttachmentBarrier(&commands, range);
|
||||
}
|
||||
attachment.texture->transitionLayout(&commands,
|
||||
range, VulkanLayout::COLOR_ATTACHMENT);
|
||||
renderPassAttachments.insert(attachment);
|
||||
|
||||
fbkey.color[i] = attachment.getImageView();
|
||||
fbkey.resolve[i] = VK_NULL_HANDLE;
|
||||
assert_invariant(fbkey.color[i]);
|
||||
@@ -1526,7 +1516,7 @@ void VulkanDriver::endRenderPass(int) {
|
||||
}
|
||||
}
|
||||
|
||||
mRenderPassFboInfo = {};
|
||||
mRenderPassFboInfo.clear();
|
||||
mCurrentRenderPass.renderTarget = nullptr;
|
||||
mCurrentRenderPass.renderPass = VK_NULL_HANDLE;
|
||||
FVK_SYSTRACE_END();
|
||||
@@ -1840,7 +1830,7 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
}
|
||||
auto layout = mResourceAllocator.handle_cast<VulkanDescriptorSetLayout*>(handle);
|
||||
layoutCount++;
|
||||
return layout->getVkLayout();
|
||||
return layout->vklayout;
|
||||
});
|
||||
auto pipelineLayout = mPipelineLayoutCache.getLayout(layoutList, program);
|
||||
|
||||
@@ -1855,6 +1845,11 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
mPipelineCache.bindLayout(pipelineLayout);
|
||||
mPipelineCache.bindPipeline(commands);
|
||||
|
||||
// Since we don't statically define scissor as part of the pipeline, we need to call scissor at
|
||||
// least once. Context: VUID-vkCmdDrawIndexed-None-07832.
|
||||
auto const& extent = rt->getExtent();
|
||||
scissor({0, 0, extent.width, extent.height});
|
||||
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
@@ -1933,9 +1928,6 @@ void VulkanDriver::scissor(Viewport scissorBox) {
|
||||
VulkanCommandBuffer& commands = mCommands.get();
|
||||
VkCommandBuffer cmdbuffer = commands.buffer();
|
||||
|
||||
// TODO: it's a common case that scissor() is called with (0, 0, maxint, maxint)
|
||||
// we should maybe have a fast path for this and avoid vkCmdSetScissor() if possible
|
||||
|
||||
// Set scissoring.
|
||||
// clamp left-bottom to 0,0 and avoid overflows
|
||||
constexpr int32_t maxvali = std::numeric_limits<int32_t>::max();
|
||||
|
||||
@@ -47,6 +47,21 @@ struct VulkanSamplerGroup;
|
||||
constexpr uint8_t MAX_RENDERTARGET_ATTACHMENT_TEXTURES =
|
||||
MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT * 2 + 1;
|
||||
|
||||
// We need to store information about a render pass to enable better barriers at the end of a
|
||||
// renderpass.
|
||||
struct RenderPassFboBundle {
|
||||
using AttachmentArray =
|
||||
CappedArray<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
|
||||
|
||||
AttachmentArray attachments;
|
||||
bool hasColorResolve = false;
|
||||
|
||||
void clear() {
|
||||
attachments.clear();
|
||||
hasColorResolve = false;
|
||||
}
|
||||
};
|
||||
|
||||
class VulkanDriver final : public DriverBase {
|
||||
public:
|
||||
static Driver* create(VulkanPlatform* platform, VulkanContext const& context,
|
||||
@@ -145,19 +160,13 @@ private:
|
||||
VulkanDescriptorSetManager mDescriptorSetManager;
|
||||
|
||||
// This is necessary for us to write to push constants after binding a pipeline.
|
||||
struct {
|
||||
struct BoundPipeline {
|
||||
VulkanProgram* program;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
DescriptorSetMask descriptorSetMask;
|
||||
} mBoundPipeline = {};
|
||||
|
||||
// We need to store information about a render pass to enable better barriers at the end of a
|
||||
// renderpass.
|
||||
struct {
|
||||
using AttachmentArray = CappedArray<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
|
||||
AttachmentArray attachments;
|
||||
bool hasColorResolve = false;
|
||||
} mRenderPassFboInfo = {};
|
||||
};
|
||||
BoundPipeline mBoundPipeline = {};
|
||||
RenderPassFboBundle mRenderPassFboInfo;
|
||||
|
||||
bool const mIsSRGBSwapChainSupported;
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace filament::backend {
|
||||
|
||||
bool VulkanFboCache::RenderPassEq::operator()(const RenderPassKey& k1,
|
||||
const RenderPassKey& k2) const {
|
||||
if (k1.initialColorLayoutMask != k2.initialColorLayoutMask) return false;
|
||||
if (k1.initialDepthLayout != k2.initialDepthLayout) return false;
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (k1.colorFormat[i] != k2.colorFormat[i]) return false;
|
||||
@@ -257,7 +258,9 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
|
||||
.storeOp = kEnableStore,
|
||||
.stencilLoadOp = kDontCare,
|
||||
.stencilStoreOp = kDisableStore,
|
||||
.initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT),
|
||||
.initialLayout = ((!discard && config.initialColorLayoutMask & (1 << i)) || clear)
|
||||
? imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT)
|
||||
: imgutil::getVkLayout(VulkanLayout::UNDEFINED),
|
||||
.finalLayout = imgutil::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,8 +42,19 @@ public:
|
||||
// RenderPassKey is a small POD representing the immutable state that is used to construct
|
||||
// a VkRenderPass. It is hashed and used as a lookup key.
|
||||
struct alignas(8) RenderPassKey {
|
||||
VulkanLayout initialDepthLayout;
|
||||
uint8_t padding[3] = {};
|
||||
// For each target, we need to know three image layouts: the layout BEFORE the pass, the
|
||||
// layout DURING the pass, and the layout AFTER the pass. Here are the rules:
|
||||
// - For depth, we explicitly specify all three layouts.
|
||||
// - Color targets have their initial image layout specified with a bitmask.
|
||||
// - For each color target, the pre-existing layout is either UNDEFINED (0) or GENERAL (1).
|
||||
// - The render pass and final images layout for color buffers is always
|
||||
// VulkanLayout::COLOR_ATTACHMENT.
|
||||
uint8_t initialColorLayoutMask;
|
||||
|
||||
// Note that if VulkanLayout grows beyond 16, we'd need to up this.
|
||||
VulkanLayout initialDepthLayout : 8;
|
||||
uint8_t padding0;
|
||||
uint8_t padding1;
|
||||
|
||||
VkFormat colorFormat[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]; // 32 bytes
|
||||
VkFormat depthFormat; // 4 bytes
|
||||
@@ -60,6 +71,7 @@ public:
|
||||
uint32_t timestamp;
|
||||
};
|
||||
static_assert(0 == MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT % 8);
|
||||
static_assert(sizeof(RenderPassKey::initialColorLayoutMask) == MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT / 8);
|
||||
static_assert(sizeof(TargetBufferFlags) == 4, "TargetBufferFlags has unexpected size.");
|
||||
static_assert(sizeof(VkFormat) == 4, "VkFormat has unexpected size.");
|
||||
static_assert(sizeof(RenderPassKey) == 56, "RenderPassKey has unexpected size.");
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
#include "VulkanHandles.h"
|
||||
|
||||
#include "VulkanConstants.h"
|
||||
|
||||
// TODO: remove this by moving DebugUtils out of VulkanDriver
|
||||
#include "VulkanDriver.h"
|
||||
|
||||
#include "VulkanMemory.h"
|
||||
#include "VulkanResourceAllocator.h"
|
||||
#include "VulkanUtility.h"
|
||||
@@ -66,6 +62,13 @@ inline void fromStageFlags(backend::ShaderStageFlags stage, descriptor_binding_t
|
||||
}
|
||||
}
|
||||
|
||||
inline VkDescriptorSetLayout createDescriptorSetLayout(VkDevice device,
|
||||
VkDescriptorSetLayoutCreateInfo const& info) {
|
||||
VkDescriptorSetLayout layout;
|
||||
vkCreateDescriptorSetLayout(device, &info, VKALLOC, &layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
inline VkShaderStageFlags getVkStage(backend::ShaderStage stage) {
|
||||
switch(stage) {
|
||||
case backend::ShaderStage::VERTEX:
|
||||
@@ -77,6 +80,61 @@ inline VkShaderStageFlags getVkStage(backend::ShaderStage stage) {
|
||||
}
|
||||
}
|
||||
|
||||
inline VkDescriptorSetLayoutCreateInfo getLayoutCreateInfo(DescriptorSetLayout const& layout) {
|
||||
// Note that the following *needs* to be static so that VkDescriptorSetLayoutCreateInfo will not
|
||||
// refer to stack memory.
|
||||
static VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS];
|
||||
uint32_t count = 0;
|
||||
|
||||
for (auto const& binding: layout.bindings) {
|
||||
VkShaderStageFlags stages = 0;
|
||||
VkDescriptorType type;
|
||||
|
||||
if ((binding.stageFlags & ShaderStageFlags::VERTEX) != ShaderStageFlags::NONE) {
|
||||
stages |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||
}
|
||||
if ((binding.stageFlags & ShaderStageFlags::FRAGMENT) != ShaderStageFlags::NONE) {
|
||||
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
}
|
||||
assert_invariant(stages != 0);
|
||||
|
||||
switch (binding.type) {
|
||||
case DescriptorType::UNIFORM_BUFFER: {
|
||||
type = (binding.flags & DescriptorFlags::DYNAMIC_OFFSET) != DescriptorFlags::NONE
|
||||
? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
|
||||
: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER: {
|
||||
type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
break;
|
||||
}
|
||||
case DescriptorType::INPUT_ATTACHMENT: {
|
||||
type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SHADER_STORAGE_BUFFER:
|
||||
PANIC_POSTCONDITION("Shader storage is not supported.");
|
||||
break;
|
||||
}
|
||||
toBind[count++] = {
|
||||
.binding = binding.binding,
|
||||
.descriptorType = type,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = stages,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
return dlinfo;
|
||||
}
|
||||
|
||||
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
|
||||
BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
||||
BitmaskGroup mask;
|
||||
@@ -108,10 +166,17 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& layout)
|
||||
: VulkanResource(VulkanResourceType::DESCRIPTOR_SET_LAYOUT),
|
||||
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VkDevice device,
|
||||
DescriptorSetLayout const& layout)
|
||||
: VulkanResource(VulkanResourceType::DESCRIPTOR_SET_LAYOUT), mDevice(device),
|
||||
vklayout(createDescriptorSetLayout(device, getLayoutCreateInfo(layout))),
|
||||
bitmask(fromBackendLayout(layout)),
|
||||
count(Count::fromLayoutBitmask(bitmask)) {}
|
||||
count(Count::fromLayoutBitmask(bitmask)) {
|
||||
}
|
||||
|
||||
VulkanDescriptorSetLayout::~VulkanDescriptorSetLayout() {
|
||||
vkDestroyDescriptorSetLayout(mDevice, vklayout, VKALLOC);
|
||||
}
|
||||
|
||||
void VulkanDescriptorSet::acquire(VulkanTexture* texture) {
|
||||
mResources.acquire(texture);
|
||||
|
||||
@@ -41,11 +41,11 @@ namespace {
|
||||
template<typename Bitmask>
|
||||
inline uint8_t collapsedCount(Bitmask const& mask) {
|
||||
static_assert(sizeof(mask) <= 64);
|
||||
constexpr uint64_t VERTEX_MASK = (1ULL << getFragmentStageShift<Bitmask>()) - 1ULL;
|
||||
constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << getFragmentStageShift<Bitmask>());
|
||||
constexpr uint64_t VERTEX_MASK = (1ULL << getVertexStageShift<Bitmask>()) - 1ULL;
|
||||
constexpr uint64_t FRAGMENT_MASK = (1ULL << getFragmentStageShift<Bitmask>()) - 1ULL;
|
||||
uint64_t val = mask.getValue();
|
||||
val = ((val & VERTEX_MASK) >> getVertexStageShift<Bitmask>()) |
|
||||
((val & FRAGMENT_MASK) >> getFragmentStageShift<Bitmask>());
|
||||
val = ((val | VERTEX_MASK) >> getVertexStageShift<Bitmask>()) |
|
||||
((val | FRAGMENT_MASK) >> getFragmentStageShift<Bitmask>());
|
||||
return (uint8_t) Bitmask(val).count();
|
||||
}
|
||||
|
||||
@@ -114,25 +114,21 @@ struct VulkanDescriptorSetLayout : public VulkanResource, HwDescriptorSetLayout
|
||||
}
|
||||
};
|
||||
|
||||
VulkanDescriptorSetLayout(DescriptorSetLayout const& layout);
|
||||
VulkanDescriptorSetLayout(VkDevice device, DescriptorSetLayout const& layout);
|
||||
|
||||
~VulkanDescriptorSetLayout() = default;
|
||||
|
||||
VkDescriptorSetLayout getVkLayout() const { return mVkLayout; }
|
||||
void setVkLayout(VkDescriptorSetLayout vklayout) { mVkLayout = vklayout; }
|
||||
~VulkanDescriptorSetLayout();
|
||||
|
||||
VkDevice const mDevice;
|
||||
VkDescriptorSetLayout const vklayout;
|
||||
Bitmask const bitmask;
|
||||
Count const count;
|
||||
|
||||
private:
|
||||
VkDescriptorSetLayout mVkLayout = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet {
|
||||
public:
|
||||
// Because we need to recycle descriptor sets not used, we allow for a callback that the "Pool"
|
||||
// can use to repackage the vk handle.
|
||||
using OnRecycle = std::function<void(VulkanDescriptorSet*)>;
|
||||
using OnRecycle = std::function<void()>;
|
||||
|
||||
VulkanDescriptorSet(VulkanResourceAllocator* allocator, VkDescriptorSet rawSet,
|
||||
OnRecycle&& onRecycleFn)
|
||||
@@ -143,7 +139,7 @@ public:
|
||||
|
||||
~VulkanDescriptorSet() {
|
||||
if (mOnRecycleFn) {
|
||||
mOnRecycleFn(this);
|
||||
mOnRecycleFn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,28 +88,12 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
|
||||
return out;
|
||||
};
|
||||
|
||||
auto const identityToChannel = [](VkComponentSwizzle val, uint8_t channelIndex) {
|
||||
if (val != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||
return val;
|
||||
}
|
||||
return IDENTITY[channelIndex];
|
||||
};
|
||||
|
||||
// We make sure all all identities are mapped into respective channels so that actual channel
|
||||
// mapping will be passed onto the output.
|
||||
VkComponentMapping const prevExplicit = {
|
||||
identityToChannel(prev.r, 0),
|
||||
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),
|
||||
compose(next.r, prev, 0),
|
||||
compose(next.g, prev, 1),
|
||||
compose(next.b, prev, 2),
|
||||
compose(next.a, prev, 3),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -597,12 +581,9 @@ bool VulkanTexture::transitionLayout(
|
||||
});
|
||||
}
|
||||
|
||||
// Even if we didn't carry out the transition, we should assume that the new layout is defined
|
||||
// through this call.
|
||||
setLayout(range, newLayout);
|
||||
|
||||
if (hasTransitions) {
|
||||
state->mTransitionFence = fence;
|
||||
setLayout(range, newLayout);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
|
||||
@@ -622,30 +603,6 @@ bool VulkanTexture::transitionLayout(
|
||||
return hasTransitions;
|
||||
}
|
||||
|
||||
void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageSubresourceRange const& range) {
|
||||
VkCommandBuffer const cmdbuf = commands->buffer();
|
||||
auto* const state = getSharedState();
|
||||
VkImageLayout const layout =
|
||||
imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.dstAccessMask =
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = state->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageSubresourceRange const& range) {
|
||||
VkCommandBuffer const cmdbuf = commands->buffer();
|
||||
@@ -706,9 +663,9 @@ VulkanLayout VulkanTexture::getLayout(uint32_t layer, uint32_t level) const {
|
||||
void VulkanTexture::print() const {
|
||||
auto* const state = getSharedState();
|
||||
uint32_t const firstLayer = 0;
|
||||
uint32_t const lastLayer = firstLayer + state->mFullViewRange.layerCount;
|
||||
uint32_t const lastLayer = firstLayer + mFullViewRange.layerCount;
|
||||
uint32_t const firstLevel = 0;
|
||||
uint32_t const lastLevel = firstLevel + state->mFullViewRange.levelCount;
|
||||
uint32_t const lastLevel = firstLevel + mFullViewRange.levelCount;
|
||||
|
||||
for (uint32_t layer = firstLayer; layer < lastLayer; ++layer) {
|
||||
for (uint32_t level = firstLevel; level < lastLevel; ++level) {
|
||||
|
||||
@@ -179,9 +179,6 @@ struct VulkanTexture : public HwTexture, VulkanResource {
|
||||
void attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageSubresourceRange const& range);
|
||||
|
||||
void samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageSubresourceRange const& range);
|
||||
|
||||
// Returns the preferred data plane of interest for all image views.
|
||||
// For now this always returns either DEPTH or COLOR.
|
||||
VkImageAspectFlags getImageAspect() const;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
@@ -122,9 +121,8 @@ public:
|
||||
return count == mCount;
|
||||
}
|
||||
|
||||
VkDescriptorSet obtainSet(VkDescriptorSetLayout vklayout) {
|
||||
auto itr = findSets(vklayout);
|
||||
if (itr != mUnused.end()) {
|
||||
VkDescriptorSet obtainSet(VulkanDescriptorSetLayout* layout) {
|
||||
if (UnusedSetMap::iterator itr = mUnused.find(layout->bitmask); itr != mUnused.end()) {
|
||||
// If we don't have any unused, then just return an empty handle.
|
||||
if (itr->second.empty()) {
|
||||
return VK_NULL_HANDLE;
|
||||
@@ -139,7 +137,7 @@ public:
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
// Creating a new set
|
||||
VkDescriptorSetLayout layouts[1] = {vklayout};
|
||||
VkDescriptorSetLayout layouts[1] = {layout->vklayout};
|
||||
VkDescriptorSetAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -156,29 +154,19 @@ public:
|
||||
return vkSet;
|
||||
}
|
||||
|
||||
void recycle(VkDescriptorSetLayout vklayout, VkDescriptorSet vkSet) {
|
||||
void recycle(BitmaskGroup const& layoutMask, 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()) {
|
||||
if (auto itr = mUnused.find(layoutMask); itr != mUnused.end()) {
|
||||
itr->second.push_back(vkSet);
|
||||
} else {
|
||||
mUnused.push_back(std::make_pair(vklayout, std::vector<VkDescriptorSet> {vkSet}));
|
||||
mUnused[layoutMask].push_back(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;
|
||||
@@ -189,7 +177,9 @@ private:
|
||||
// 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.
|
||||
// This maps a layout ot a list of descriptor sets allocated for that layout.
|
||||
using UnusedSetMap = std::unordered_map<BitmaskGroup, std::vector<VkDescriptorSet>,
|
||||
BitmaskGroupHashFn, BitmaskGroupEqual>;
|
||||
UnusedSetMap mUnused;
|
||||
};
|
||||
|
||||
@@ -206,13 +196,12 @@ public:
|
||||
: mDevice(device) {}
|
||||
|
||||
VkDescriptorSet obtainSet(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) {
|
||||
if (auto set = pool->obtainSet(layout); set != VK_NULL_HANDLE) {
|
||||
return set;
|
||||
}
|
||||
if (!sameTypePool || sameTypePool->capacity() < pool->capacity()) {
|
||||
@@ -230,18 +219,18 @@ public:
|
||||
mPools.push_back(std::make_unique<DescriptorPool>(mDevice,
|
||||
DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity));
|
||||
auto& pool = mPools.back();
|
||||
auto ret = pool->obtainSet(vklayout);
|
||||
auto ret = pool->obtainSet(layout);
|
||||
assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void recycle(DescriptorCount const& count, VkDescriptorSetLayout vklayout,
|
||||
void recycle(DescriptorCount const& count, BitmaskGroup const& layoutMask,
|
||||
VkDescriptorSet vkSet) {
|
||||
for (auto& pool: mPools) {
|
||||
if (!pool->canAllocate(count)) {
|
||||
continue;
|
||||
}
|
||||
pool->recycle(vklayout, vkSet);
|
||||
pool->recycle(layoutMask, vkSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -258,93 +247,6 @@ struct Equal {
|
||||
}
|
||||
};
|
||||
|
||||
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 < getFragmentStageShift<Bitmask>()) {
|
||||
binding = (uint32_t) index;
|
||||
stages |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||
auto fragIndex = index + 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 - 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;
|
||||
}
|
||||
|
||||
class DescriptorSetLayoutManager {
|
||||
public:
|
||||
DescriptorSetLayoutManager(VkDevice device)
|
||||
: mDevice(device) {}
|
||||
|
||||
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout* layout) {
|
||||
auto const& bitmasks = layout->bitmask;
|
||||
if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
auto vklayout = createLayout(mDevice, layout->bitmask);
|
||||
mVkLayouts[layout->bitmask] = vklayout;
|
||||
return vklayout;
|
||||
}
|
||||
|
||||
~DescriptorSetLayoutManager() {
|
||||
for (auto& itr: mVkLayouts) {
|
||||
vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice mDevice;
|
||||
tsl::robin_map<BitmaskGroup, VkDescriptorSetLayout, BitmaskGroupHashFn, BitmaskGroupEqual>
|
||||
mVkLayouts;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class VulkanDescriptorSetManager::Impl {
|
||||
@@ -353,27 +255,22 @@ private:
|
||||
private:
|
||||
using TextureBundle = std::pair<VulkanTexture*, VkImageSubresourceRange>;
|
||||
public:
|
||||
DescriptorSetHistory()
|
||||
: dynamicUboCount(0),
|
||||
mResources(nullptr) {}
|
||||
DescriptorSetHistory() : mResources(nullptr) {}
|
||||
|
||||
DescriptorSetHistory(UniformBufferBitmask const& dynamicUbo, uint8_t uniqueDynamicUboCount,
|
||||
VulkanResourceAllocator* allocator, VulkanDescriptorSet* set)
|
||||
: dynamicUboMask(dynamicUbo),
|
||||
dynamicUboCount(uniqueDynamicUboCount),
|
||||
DescriptorSetHistory(BitmaskGroup const& mask, VulkanResourceAllocator* allocator,
|
||||
VulkanDescriptorSet* set)
|
||||
: dynamicUboMask(mask.dynamicUbo),
|
||||
mResources(allocator),
|
||||
mSet(set),
|
||||
mBound(false) {
|
||||
assert_invariant(set);
|
||||
// initial state is unbound.
|
||||
mResources.acquire(mSet);
|
||||
unbind();
|
||||
}
|
||||
|
||||
~DescriptorSetHistory() {
|
||||
if (mSet) {
|
||||
mResources.clear();
|
||||
}
|
||||
assert_invariant(mSet);
|
||||
mResources.clear();
|
||||
}
|
||||
|
||||
void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
|
||||
@@ -389,7 +286,7 @@ private:
|
||||
void bind(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, uint8_t index) noexcept {
|
||||
VkCommandBuffer const cmdbuffer = commands->buffer();
|
||||
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout,
|
||||
index, 1, &mSet->vkSet, dynamicUboCount, mOffsets.data());
|
||||
index, 1, &mSet->vkSet, (uint32_t) dynamicUboMask.count(), mOffsets.data());
|
||||
|
||||
commands->acquire(mSet);
|
||||
mResources.clear();
|
||||
@@ -404,7 +301,6 @@ private:
|
||||
bool bound() const noexcept { return mBound; }
|
||||
|
||||
UniformBufferBitmask const dynamicUboMask;
|
||||
uint8_t const dynamicUboCount;
|
||||
|
||||
private:
|
||||
FixedSizeVulkanResourceManager<1> mResources;
|
||||
@@ -440,14 +336,13 @@ public:
|
||||
Impl(VkDevice device, VulkanResourceAllocator* resourceAllocator)
|
||||
: mDevice(device),
|
||||
mResourceAllocator(resourceAllocator),
|
||||
mLayoutManager(device),
|
||||
mDescriptorPool(device) {}
|
||||
|
||||
// bind() is not really binding the set but just stashing until we have all the info
|
||||
// (pipelinelayout).
|
||||
void bind(uint8_t setIndex, VulkanDescriptorSet* set,
|
||||
backend::DescriptorSetOffsetArray&& offsets) {
|
||||
auto& history = mHistory[set];
|
||||
auto& history = mHistory[set->vkSet];
|
||||
history.setOffsets(std::move(offsets));
|
||||
|
||||
auto lastHistory = mStashedSets[setIndex];
|
||||
@@ -495,7 +390,7 @@ public:
|
||||
};
|
||||
|
||||
VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
auto& history = mHistory[set];
|
||||
auto& history = mHistory[set->vkSet];
|
||||
|
||||
if (history.dynamicUboMask.test(binding)) {
|
||||
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
@@ -543,7 +438,7 @@ public:
|
||||
};
|
||||
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
|
||||
set->acquire(texture);
|
||||
mHistory[set].write(binding);
|
||||
mHistory[set->vkSet].write(binding);
|
||||
}
|
||||
|
||||
void updateInputAttachment(VulkanDescriptorSet* set, VulkanAttachment attachment) noexcept {
|
||||
@@ -567,33 +462,22 @@ public:
|
||||
void createSet(Handle<HwDescriptorSet> handle, VulkanDescriptorSetLayout* layout) {
|
||||
auto const vkSet = mDescriptorPool.obtainSet(layout);
|
||||
auto const& count = layout->count;
|
||||
auto const vklayout = layout->getVkLayout();
|
||||
VulkanDescriptorSet* set =
|
||||
mResourceAllocator->construct<VulkanDescriptorSet>(handle, mResourceAllocator,
|
||||
vkSet, [vkSet, count, vklayout, this](VulkanDescriptorSet* set) {
|
||||
eraseSetFromHistory(set);
|
||||
mDescriptorPool.recycle(count, vklayout, vkSet);
|
||||
});
|
||||
auto const& layoutMask = layout->bitmask;
|
||||
auto set = mResourceAllocator->construct<VulkanDescriptorSet>(handle, mResourceAllocator,
|
||||
vkSet, [vkSet, count, layoutMask, this]() {
|
||||
mHistory.erase(vkSet);
|
||||
mDescriptorPool.recycle(count, layoutMask, vkSet);
|
||||
});
|
||||
mHistory.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(set),
|
||||
std::forward_as_tuple(layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
|
||||
mResourceAllocator, set));
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(vkSet),
|
||||
std::forward_as_tuple(layout->bitmask, mResourceAllocator, set));
|
||||
}
|
||||
|
||||
void destroySet(Handle<HwDescriptorSet> handle) {
|
||||
VulkanDescriptorSet* set = mResourceAllocator->handle_cast<VulkanDescriptorSet*>(handle);
|
||||
eraseSetFromHistory(set);
|
||||
}
|
||||
|
||||
void initVkLayout(VulkanDescriptorSetLayout* layout) {
|
||||
layout->setVkLayout(mLayoutManager.getVkLayout(layout));
|
||||
}
|
||||
|
||||
private:
|
||||
inline void eraseSetFromHistory(VulkanDescriptorSet* set) {
|
||||
DescriptorSetHistory* history = &mHistory[set];
|
||||
mHistory.erase(set);
|
||||
DescriptorSetHistory* history = &mHistory[set->vkSet];
|
||||
mHistory.erase(set->vkSet);
|
||||
|
||||
for (uint8_t i = 0; i < mStashedSets.size(); ++i) {
|
||||
if (mStashedSets[i] == history) {
|
||||
@@ -602,13 +486,14 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VkDevice mDevice;
|
||||
VulkanResourceAllocator* mResourceAllocator;
|
||||
DescriptorSetLayoutManager mLayoutManager;
|
||||
DescriptorInfinitePool mDescriptorPool;
|
||||
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
||||
std::unordered_map<VulkanDescriptorSet*, DescriptorSetHistory> mHistory;
|
||||
DescriptorSetHistoryArray mStashedSets = {};
|
||||
std::unordered_map<VkDescriptorSet, DescriptorSetHistory> mHistory;
|
||||
DescriptorSetHistoryArray mStashedSets;
|
||||
|
||||
BoundInfo mLastBoundInfo;
|
||||
|
||||
@@ -665,9 +550,5 @@ void VulkanDescriptorSetManager::destroySet(Handle<HwDescriptorSet> handle) {
|
||||
mImpl->destroySet(handle);
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetManager::initVkLayout(VulkanDescriptorSetLayout* layout) {
|
||||
mImpl->initVkLayout(layout);
|
||||
}
|
||||
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -68,8 +68,6 @@ public:
|
||||
|
||||
void destroySet(Handle<HwDescriptorSet> handle);
|
||||
|
||||
void initVkLayout(VulkanDescriptorSetLayout* layout);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl* mImpl;
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
Builder& mipLevel(AttachmentPoint attachment, uint8_t level) noexcept;
|
||||
|
||||
/**
|
||||
* Sets the face for cubemap textures at the given attachment point.
|
||||
* Sets the cubemap face for a given attachment point.
|
||||
*
|
||||
* @param attachment The attachment point.
|
||||
* @param face The associated cubemap face.
|
||||
@@ -127,12 +127,7 @@ public:
|
||||
Builder& face(AttachmentPoint attachment, CubemapFace face) noexcept;
|
||||
|
||||
/**
|
||||
* Sets an index of a single layer for 2d array, cubemap array, and 3d textures at the given
|
||||
* attachment point.
|
||||
*
|
||||
* For cubemap array textures, layer is translated into an array index and face according to
|
||||
* - index: layer / 6
|
||||
* - face: layer % 6
|
||||
* Sets the layer for a given attachment point (for 3D textures).
|
||||
*
|
||||
* @param attachment The attachment point.
|
||||
* @param layer The associated cubemap layer.
|
||||
@@ -140,19 +135,6 @@ public:
|
||||
*/
|
||||
Builder& layer(AttachmentPoint attachment, uint32_t layer) noexcept;
|
||||
|
||||
/**
|
||||
* Sets the starting index of the 2d array textures for multiview at the given attachment
|
||||
* point.
|
||||
*
|
||||
* This requires COLOR and DEPTH attachments (if set) to be of 2D array textures.
|
||||
*
|
||||
* @param attachment The attachment point.
|
||||
* @param layerCount The number of layers used for multiview, starting from baseLayer.
|
||||
* @param baseLayer The starting index of the 2d array texture.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& multiview(AttachmentPoint attachment, uint8_t layerCount, uint8_t baseLayer = 0) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the RenderTarget object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -56,12 +56,7 @@ class Bimap {
|
||||
}
|
||||
};
|
||||
|
||||
using ForwardMap = tsl::robin_map<
|
||||
KeyDelegate, Value,
|
||||
KeyHasherDelegate,
|
||||
std::equal_to<KeyDelegate>,
|
||||
std::allocator<std::pair<KeyDelegate, Value>>,
|
||||
true>;
|
||||
using ForwardMap = tsl::robin_map<KeyDelegate, Value, KeyHasherDelegate>;
|
||||
using BackwardMap = tsl::robin_map<Value, KeyDelegate, ValueHash>;
|
||||
|
||||
Allocator mAllocator;
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 "HwDescriptorSetLayoutFactory.h"
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace utils;
|
||||
using namespace backend;
|
||||
|
||||
size_t HwDescriptorSetLayoutFactory::Parameters::hash() const noexcept {
|
||||
return utils::hash::murmurSlow(
|
||||
reinterpret_cast<uint8_t const *>(dsl.bindings.data()),
|
||||
dsl.bindings.size() * sizeof(backend::DescriptorSetLayoutBinding),
|
||||
42);
|
||||
}
|
||||
|
||||
bool operator==(HwDescriptorSetLayoutFactory::Parameters const& lhs,
|
||||
HwDescriptorSetLayoutFactory::Parameters const& rhs) noexcept {
|
||||
return (lhs.dsl.bindings.size() == rhs.dsl.bindings.size()) &&
|
||||
std::equal(
|
||||
lhs.dsl.bindings.begin(), lhs.dsl.bindings.end(),
|
||||
rhs.dsl.bindings.begin());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
HwDescriptorSetLayoutFactory::HwDescriptorSetLayoutFactory()
|
||||
: mArena("HwDescriptorSetLayoutFactory::mArena", SET_ARENA_SIZE),
|
||||
mBimap(mArena) {
|
||||
mBimap.reserve(256);
|
||||
}
|
||||
|
||||
HwDescriptorSetLayoutFactory::~HwDescriptorSetLayoutFactory() noexcept = default;
|
||||
|
||||
void HwDescriptorSetLayoutFactory::terminate(DriverApi&) noexcept {
|
||||
assert_invariant(mBimap.empty());
|
||||
}
|
||||
|
||||
auto HwDescriptorSetLayoutFactory::create(DriverApi& driver,
|
||||
backend::DescriptorSetLayout dsl) noexcept -> Handle {
|
||||
|
||||
std::sort(dsl.bindings.begin(), dsl.bindings.end(),
|
||||
[](auto&& lhs, auto&& rhs) {
|
||||
return lhs.binding < rhs.binding;
|
||||
});
|
||||
|
||||
// see if we already have seen this RenderPrimitive
|
||||
Key const key({ dsl });
|
||||
auto pos = mBimap.find(key);
|
||||
|
||||
// the common case is that we've never seen it (i.e.: no reuse)
|
||||
if (UTILS_LIKELY(pos == mBimap.end())) {
|
||||
auto handle = driver.createDescriptorSetLayout(std::move(dsl));
|
||||
mBimap.insert(key, { handle });
|
||||
return handle;
|
||||
}
|
||||
|
||||
++(pos->first.pKey->refs);
|
||||
|
||||
return pos->second.handle;
|
||||
}
|
||||
|
||||
void HwDescriptorSetLayoutFactory::destroy(DriverApi& driver, Handle handle) noexcept {
|
||||
// look for this handle in our map
|
||||
auto pos = mBimap.find(Value{ handle });
|
||||
if (--pos->second.pKey->refs == 0) {
|
||||
mBimap.erase(pos);
|
||||
driver.destroyDescriptorSetLayout(handle);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_HWDESCRIPTORSETLAYOUTFACTORY_H
|
||||
#define TNT_FILAMENT_HWDESCRIPTORSETLAYOUTFACTORY_H
|
||||
|
||||
#include "Bimap.h"
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
class FEngine;
|
||||
|
||||
class HwDescriptorSetLayoutFactory {
|
||||
public:
|
||||
using Handle = backend::DescriptorSetLayoutHandle;
|
||||
|
||||
HwDescriptorSetLayoutFactory();
|
||||
~HwDescriptorSetLayoutFactory() noexcept;
|
||||
|
||||
HwDescriptorSetLayoutFactory(HwDescriptorSetLayoutFactory const& rhs) = delete;
|
||||
HwDescriptorSetLayoutFactory(HwDescriptorSetLayoutFactory&& rhs) noexcept = delete;
|
||||
HwDescriptorSetLayoutFactory& operator=(HwDescriptorSetLayoutFactory const& rhs) = delete;
|
||||
HwDescriptorSetLayoutFactory& operator=(HwDescriptorSetLayoutFactory&& rhs) noexcept = delete;
|
||||
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
struct Parameters { // 16 bytes + heap allocations
|
||||
backend::DescriptorSetLayout dsl;
|
||||
size_t hash() const noexcept;
|
||||
};
|
||||
|
||||
friend bool operator==(Parameters const& lhs, Parameters const& rhs) noexcept;
|
||||
|
||||
Handle create(backend::DriverApi& driver, backend::DescriptorSetLayout dsl) noexcept;
|
||||
|
||||
void destroy(backend::DriverApi& driver, Handle handle) noexcept;
|
||||
|
||||
private:
|
||||
struct Key { // 24 bytes
|
||||
// The key should not be copyable, unfortunately due to how the Bimap works we have
|
||||
// to copy-construct it once.
|
||||
Key(Key const&) = default;
|
||||
Key& operator=(Key const&) = delete;
|
||||
Key& operator=(Key&&) noexcept = delete;
|
||||
explicit Key(Parameters const& params) : params(params), refs(1) { }
|
||||
Parameters params;
|
||||
mutable uint32_t refs; // 4 bytes
|
||||
bool operator==(Key const& rhs) const noexcept {
|
||||
return params == rhs.params;
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyHasher {
|
||||
size_t operator()(Key const& p) const noexcept {
|
||||
return p.params.hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct Value { // 4 bytes
|
||||
Handle handle;
|
||||
};
|
||||
|
||||
struct ValueHasher {
|
||||
size_t operator()(Value const v) const noexcept {
|
||||
return std::hash<Handle::HandleId>()(v.handle.getId());
|
||||
}
|
||||
};
|
||||
|
||||
friend bool operator==(Value const lhs, Value const rhs) noexcept {
|
||||
return lhs.handle == rhs.handle;
|
||||
}
|
||||
|
||||
// Size of the arena used for the "set" part of the bimap
|
||||
// about ~1K entries before fall back to heap
|
||||
static constexpr size_t SET_ARENA_SIZE = 24 * 1024;
|
||||
|
||||
// Arena for the set<>, using a pool allocator inside a heap area.
|
||||
using PoolAllocatorArena = utils::Arena<
|
||||
utils::PoolAllocatorWithFallback<sizeof(Key)>,
|
||||
utils::LockingPolicy::NoLock,
|
||||
utils::TrackingPolicy::Untracked,
|
||||
utils::AreaPolicy::HeapArea>;
|
||||
|
||||
|
||||
// Arena where the set memory is allocated
|
||||
PoolAllocatorArena mArena;
|
||||
|
||||
// The special Bimap
|
||||
Bimap<Key, Value, KeyHasher, ValueHasher,
|
||||
utils::STLAllocator<Key, PoolAllocatorArena>> mBimap;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_HWDESCRIPTORSETLAYOUTFACTORY_H
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
struct Parameters { // 12 bytes
|
||||
struct Parameters { // 20 bytes
|
||||
backend::VertexBufferHandle vbh; // 4
|
||||
backend::IndexBufferHandle ibh; // 4
|
||||
backend::PrimitiveType type; // 4
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
void destroy(backend::DriverApi& driver, Handle handle) noexcept;
|
||||
|
||||
private:
|
||||
struct Key { // 16 bytes
|
||||
struct Key {
|
||||
// The key should not be copyable, unfortunately due to how the Bimap works we have
|
||||
// to copy-construct it once.
|
||||
Key(Key const&) = default;
|
||||
@@ -100,8 +100,7 @@ private:
|
||||
}
|
||||
|
||||
// Size of the arena used for the "set" part of the bimap
|
||||
// about ~65K entry before fall back to heap
|
||||
static constexpr size_t SET_ARENA_SIZE = 1 * 1024 * 1024;
|
||||
static constexpr size_t SET_ARENA_SIZE = 4 * 1024 * 1024;
|
||||
|
||||
// Arena for the set<>, using a pool allocator inside a heap area.
|
||||
using PoolAllocatorArena = utils::Arena<
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
struct Parameters { // 132 bytes
|
||||
struct Parameters { // 136 bytes
|
||||
uint8_t bufferCount;
|
||||
uint8_t attributeCount;
|
||||
uint8_t padding[2] = {};
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
void destroy(backend::DriverApi& driver, Handle handle) noexcept;
|
||||
|
||||
private:
|
||||
struct Key { // 136 bytes
|
||||
struct Key { // 140 bytes
|
||||
// The key should not be copyable, unfortunately due to how the Bimap works we have
|
||||
// to copy-construct it once.
|
||||
Key(Key const&) = default;
|
||||
@@ -101,8 +101,7 @@ private:
|
||||
}
|
||||
|
||||
// Size of the arena used for the "set" part of the bimap
|
||||
// about ~15K entry before fall back to heap
|
||||
static constexpr size_t SET_ARENA_SIZE = 2 * 1024 * 1024;
|
||||
static constexpr size_t SET_ARENA_SIZE = 4 * 1024 * 1024;
|
||||
|
||||
// Arena for the set<>, using a pool allocator inside a heap area.
|
||||
using PoolAllocatorArena = utils::Arena<
|
||||
|
||||
@@ -250,16 +250,6 @@ PostProcessManager::PostProcessManager(FEngine& engine) noexcept
|
||||
|
||||
PostProcessManager::~PostProcessManager() noexcept = default;
|
||||
|
||||
void PostProcessManager::setFrameUniforms(backend::DriverApi& driver,
|
||||
TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
|
||||
mPostProcessDescriptorSet.setFrameUniforms(driver, uniforms);
|
||||
mSsrPassDescriptorSet.setFrameUniforms(uniforms);
|
||||
}
|
||||
|
||||
void PostProcessManager::bindPostProcessDescriptorSet(backend::DriverApi& driver) const noexcept {
|
||||
mPostProcessDescriptorSet.bind(driver);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void PostProcessManager::registerPostProcessMaterial(std::string_view name,
|
||||
MaterialInfo const& info) {
|
||||
@@ -391,7 +381,7 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept {
|
||||
++first;
|
||||
}
|
||||
|
||||
mPostProcessDescriptorSet.terminate(engine.getDescriptorSetLayoutFactory(), driver);
|
||||
mPostProcessDescriptorSet.terminate(driver);
|
||||
mSsrPassDescriptorSet.terminate(driver);
|
||||
}
|
||||
|
||||
@@ -622,6 +612,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
userViewMatrix = cameraInfo.getUserViewMatrix(), uvFromClipMatrix, historyProjection,
|
||||
options, passBuilder = passBuilder]
|
||||
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
|
||||
// set our frame uniforms in our descriptor-set
|
||||
assert_invariant(mFrameUniforms);
|
||||
mSsrPassDescriptorSet.setFrameUniforms(*mFrameUniforms);
|
||||
|
||||
// set structure sampler
|
||||
mSsrPassDescriptorSet.prepareStructure(data.structure ?
|
||||
resources.getTexture(data.structure) : getOneTexture());
|
||||
|
||||
@@ -103,6 +103,14 @@ public:
|
||||
void init() noexcept;
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void bindPostProcessDescriptorSet(backend::DriverApi& driver) const noexcept {
|
||||
assert_invariant(mFrameUniforms);
|
||||
if (mFrameUniforms) {
|
||||
mPostProcessDescriptorSet.setFrameUniforms(driver, *mFrameUniforms);
|
||||
mPostProcessDescriptorSet.bind(driver);
|
||||
}
|
||||
}
|
||||
|
||||
void configureTemporalAntiAliasingMaterial(
|
||||
TemporalAntiAliasingOptions const& taaOptions) noexcept;
|
||||
|
||||
@@ -373,16 +381,16 @@ public:
|
||||
render(out, combo.first, combo.second, driver);
|
||||
}
|
||||
|
||||
void setFrameUniforms(backend::DriverApi& driver,
|
||||
TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
|
||||
|
||||
void bindPostProcessDescriptorSet(backend::DriverApi& driver) const noexcept;
|
||||
void setFrameUniforms(TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
|
||||
mFrameUniforms = std::addressof(uniforms);
|
||||
}
|
||||
|
||||
private:
|
||||
FEngine& mEngine;
|
||||
|
||||
mutable SsrPassDescriptorSet mSsrPassDescriptorSet;
|
||||
mutable PostProcessDescriptorSet mPostProcessDescriptorSet;
|
||||
TypedUniformBuffer<PerViewUib>* mFrameUniforms = nullptr;
|
||||
|
||||
struct BilateralPassConfig {
|
||||
uint8_t kernelSize = 11;
|
||||
|
||||
+15
-24
@@ -929,17 +929,15 @@ void RenderPass::Executor::execute(FEngine& engine,
|
||||
|
||||
// Maximum space occupied in the CircularBuffer by a single `Command`. This must be
|
||||
// reevaluated when the inner loop below adds DriverApi commands or when we change the
|
||||
// CommandStream protocol. Currently, the maximum is 248 bytes.
|
||||
// CommandStream protocol. Currently, the maximum is 320 bytes.
|
||||
// The batch size is calculated by adding the size of all commands that can possibly be
|
||||
// emitted per draw call:
|
||||
constexpr size_t const maxCommandSizeInBytes =
|
||||
sizeof(CustomCommand) +
|
||||
sizeof(COMMAND_TYPE(scissor)) +
|
||||
sizeof(COMMAND_TYPE(bindDescriptorSet)) +
|
||||
sizeof(COMMAND_TYPE(bindDescriptorSet)) +
|
||||
sizeof(COMMAND_TYPE(bindPipeline)) +
|
||||
sizeof(COMMAND_TYPE(bindRenderPrimitive)) +
|
||||
sizeof(COMMAND_TYPE(bindDescriptorSet)) + backend::CustomCommand::align(sizeof(NoopCommand) + 8) +
|
||||
sizeof(COMMAND_TYPE(setPushConstant)) +
|
||||
sizeof(COMMAND_TYPE(bindRenderPrimitive)) +
|
||||
sizeof(COMMAND_TYPE(draw2));
|
||||
|
||||
|
||||
@@ -1019,25 +1017,18 @@ void RenderPass::Executor::execute(FEngine& engine,
|
||||
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_MATERIAL] =
|
||||
ma->getDescriptorSetLayout().getHandle();
|
||||
|
||||
if (UTILS_UNLIKELY(ma->getMaterialDomain() == MaterialDomain::POST_PROCESS)) {
|
||||
// It is possible to get a post-process material here (even though it's
|
||||
// not technically a public API yet, it is used by the IBLPrefilterLibrary.
|
||||
// Ideally we would have a more formal compute API). In this case, we need
|
||||
// to set the post-process descriptor-set.
|
||||
engine.getPostProcessManager().bindPostProcessDescriptorSet(driver);
|
||||
} else {
|
||||
// If we have a ColorPassDescriptorSet we use it to bind the per-view
|
||||
// descriptor-set (ideally only if it changed). If we don't, it means
|
||||
// the descriptor-set is already bound and the layout we got from the
|
||||
// material above should match. This is the case for situations where we
|
||||
// have a known per-view descriptor-set layout, e.g.: shadow-maps, ssr and
|
||||
// structure passes.
|
||||
if (mColorPassDescriptorSet) {
|
||||
// We have a ColorPassDescriptorSet, we need to go through it for binding
|
||||
// the per-view descriptor-set because its layout can change based on the
|
||||
// material.
|
||||
mColorPassDescriptorSet->bind(driver, ma->getPerViewLayoutIndex());
|
||||
}
|
||||
// If we have a ColorPassDescriptorSet we use it to bind the per-view
|
||||
// descriptor-set (ideally only if it changed). If we don't, it means
|
||||
// the descriptor-set is already bound and the layout we got from the
|
||||
// material above should match. This is the case for situations where we
|
||||
// have a known per-view descriptor-set layout, e.g.: shadow-maps, ssr and
|
||||
// structure passes.
|
||||
|
||||
if (mColorPassDescriptorSet) {
|
||||
// We have a ColorPassDescriptorSet, we need to go through it for binding
|
||||
// the per-view descriptor-set because its layout can change based on the
|
||||
// material.
|
||||
mColorPassDescriptorSet->bind(driver, ma->getPerViewLayoutIndex());
|
||||
}
|
||||
|
||||
// Each MaterialInstance has its own descriptor set. This binds it.
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_TYPEDBUFFER_H
|
||||
#define TNT_FILAMENT_TYPEDBUFFER_H
|
||||
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <backend/BufferDescriptor.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
template<typename T, size_t N = 1>
|
||||
class TypedBuffer { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
public:
|
||||
|
||||
T& itemAt(size_t i) noexcept {
|
||||
mSomethingDirty = true;
|
||||
return mBuffer[i];
|
||||
}
|
||||
|
||||
T& edit() noexcept {
|
||||
return itemAt(0);
|
||||
}
|
||||
|
||||
// size of the uniform buffer in bytes
|
||||
size_t getSize() const noexcept { return sizeof(T) * N; }
|
||||
|
||||
// return if any uniform has been changed
|
||||
bool isDirty() const noexcept { return mSomethingDirty; }
|
||||
|
||||
// mark the whole buffer as "clean" (no modified uniforms)
|
||||
void clean() const noexcept { mSomethingDirty = false; }
|
||||
|
||||
// helper functions
|
||||
|
||||
backend::BufferDescriptor toBufferDescriptor(backend::DriverApi& driver) const noexcept {
|
||||
return toBufferDescriptor(driver, 0, getSize());
|
||||
}
|
||||
|
||||
// copy the UBO data and cleans the dirty bits
|
||||
backend::BufferDescriptor toBufferDescriptor(
|
||||
backend::DriverApi& driver, size_t offset, size_t size) const noexcept {
|
||||
backend::BufferDescriptor p;
|
||||
p.size = size;
|
||||
p.buffer = driver.allocate(p.size); // TODO: use out-of-line buffer if too large
|
||||
memcpy(p.buffer, reinterpret_cast<const char*>(mBuffer) + offset, p.size); // inlined
|
||||
clean();
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
T mBuffer[N];
|
||||
mutable bool mSomethingDirty = false;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_TYPEDBUFFER_H
|
||||
@@ -345,17 +345,14 @@ void FEngine::init() {
|
||||
|
||||
|
||||
mPerViewDescriptorSetLayoutSsrVariant = {
|
||||
mHwDescriptorSetLayoutFactory,
|
||||
driverApi,
|
||||
descriptor_sets::getSsrVariantLayout() };
|
||||
|
||||
mPerViewDescriptorSetLayoutDepthVariant = {
|
||||
mHwDescriptorSetLayoutFactory,
|
||||
driverApi,
|
||||
descriptor_sets::getDepthVariantLayout() };
|
||||
|
||||
mPerRenderableDescriptorSetLayout = {
|
||||
mHwDescriptorSetLayoutFactory,
|
||||
driverApi,
|
||||
descriptor_sets::getPerRenderableLayout() };
|
||||
|
||||
@@ -486,9 +483,9 @@ void FEngine::shutdown() {
|
||||
mLightManager.terminate(); // free-up all lights
|
||||
mCameraManager.terminate(*this); // free-up all cameras
|
||||
|
||||
mPerViewDescriptorSetLayoutDepthVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
mPerViewDescriptorSetLayoutSsrVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
mPerRenderableDescriptorSetLayout.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
mPerViewDescriptorSetLayoutDepthVariant.terminate(driver);
|
||||
mPerViewDescriptorSetLayoutSsrVariant.terminate(driver);
|
||||
mPerRenderableDescriptorSetLayout.terminate(driver);
|
||||
|
||||
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
|
||||
|
||||
@@ -589,10 +586,12 @@ void FEngine::prepare() {
|
||||
});
|
||||
}
|
||||
|
||||
mMaterials.forEach([](FMaterial* material) {
|
||||
// Commit default material instances.
|
||||
mMaterials.forEach([&driver](FMaterial* material) {
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
material->checkProgramEdits();
|
||||
#endif
|
||||
material->getDefaultInstance()->commit(driver);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -835,15 +834,6 @@ FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material,
|
||||
return p;
|
||||
}
|
||||
|
||||
FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material) noexcept {
|
||||
FMaterialInstance* p = mHeapAllocator.make<FMaterialInstance>(*this, material);
|
||||
if (UTILS_UNLIKELY(p)) { // should never happen
|
||||
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
|
||||
pos.first->second.insert(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Objects created without a Builder
|
||||
*/
|
||||
@@ -1098,32 +1088,29 @@ bool FEngine::destroy(const FInstanceBuffer* p){
|
||||
UTILS_NOINLINE
|
||||
bool FEngine::destroy(const FMaterial* ptr) {
|
||||
if (ptr == nullptr) return true;
|
||||
bool const success = terminateAndDestroy(ptr, mMaterials);
|
||||
if (success) {
|
||||
auto pos = mMaterialInstances.find(ptr);
|
||||
if (pos != mMaterialInstances.cend()) {
|
||||
// ensure we've destroyed all instances before destroying the material
|
||||
if (!ASSERT_PRECONDITION_NON_FATAL(pos->second.empty(),
|
||||
"destroying material \"%s\" but %u instances still alive",
|
||||
ptr->getName().c_str(), (*pos).second.size())) {
|
||||
return false;
|
||||
}
|
||||
auto pos = mMaterialInstances.find(ptr);
|
||||
if (pos != mMaterialInstances.cend()) {
|
||||
// ensure we've destroyed all instances before destroying the material
|
||||
if (!ASSERT_PRECONDITION_NON_FATAL(pos->second.empty(),
|
||||
"destroying material \"%s\" but %u instances still alive",
|
||||
ptr->getName().c_str(), (*pos).second.size())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
return terminateAndDestroy(ptr, mMaterials);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
bool FEngine::destroy(const FMaterialInstance* ptr) {
|
||||
if (ptr == nullptr) return true;
|
||||
if (ptr->isDefaultInstance()) return false;
|
||||
auto pos = mMaterialInstances.find(ptr->getMaterial());
|
||||
assert_invariant(pos != mMaterialInstances.cend());
|
||||
if (pos != mMaterialInstances.cend()) {
|
||||
return terminateAndDestroy(ptr, pos->second);
|
||||
}
|
||||
// this shouldn't happen, this would be double-free
|
||||
return false;
|
||||
// if we don't find this instance's material it might be because it's the default instance
|
||||
// in which case it fine to ignore.
|
||||
return true;
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "DFG.h"
|
||||
#include "PostProcessManager.h"
|
||||
#include "ResourceList.h"
|
||||
#include "HwDescriptorSetLayoutFactory.h"
|
||||
#include "HwVertexBufferInfoFactory.h"
|
||||
|
||||
#include "components/CameraManager.h"
|
||||
@@ -299,12 +298,9 @@ public:
|
||||
void createLight(const LightManager::Builder& builder, utils::Entity entity);
|
||||
|
||||
FRenderer* createRenderer() noexcept;
|
||||
|
||||
FMaterialInstance* createMaterialInstance(const FMaterial* material,
|
||||
const FMaterialInstance* other, const char* name) noexcept;
|
||||
|
||||
FMaterialInstance* createMaterialInstance(const FMaterial* material) noexcept;
|
||||
|
||||
FScene* createScene() noexcept;
|
||||
FView* createView() noexcept;
|
||||
FFence* createFence() noexcept;
|
||||
@@ -451,10 +447,6 @@ public:
|
||||
return mHwVertexBufferInfoFactory;
|
||||
}
|
||||
|
||||
HwDescriptorSetLayoutFactory& getDescriptorSetLayoutFactory() noexcept {
|
||||
return mHwDescriptorSetLayoutFactory;
|
||||
}
|
||||
|
||||
DescriptorSetLayout const& getPerViewDescriptorSetLayoutDepthVariant() const noexcept {
|
||||
return mPerViewDescriptorSetLayoutDepthVariant;
|
||||
}
|
||||
@@ -536,7 +528,6 @@ private:
|
||||
FCameraManager mCameraManager;
|
||||
std::shared_ptr<ResourceAllocatorDisposer> mResourceAllocatorDisposer;
|
||||
HwVertexBufferInfoFactory mHwVertexBufferInfoFactory;
|
||||
HwDescriptorSetLayoutFactory mHwDescriptorSetLayoutFactory;
|
||||
DescriptorSetLayout mPerViewDescriptorSetLayoutDepthVariant;
|
||||
DescriptorSetLayout mPerViewDescriptorSetLayoutSsrVariant;
|
||||
DescriptorSetLayout mPerRenderableDescriptorSetLayout;
|
||||
|
||||
@@ -327,6 +327,9 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
processDepthVariants(engine, parser);
|
||||
processDescriptorSets(engine, parser);
|
||||
|
||||
// we can only initialize the default instance once we're initialized ourselves
|
||||
new(&mDefaultInstanceStorage) FMaterialInstance(engine, this);
|
||||
|
||||
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
|
||||
mIsVariantLit,
|
||||
mReflectionMode == ReflectionMode::SCREEN_SPACE ||
|
||||
@@ -343,7 +346,9 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
#endif
|
||||
}
|
||||
|
||||
FMaterial::~FMaterial() noexcept = default;
|
||||
FMaterial::~FMaterial() noexcept {
|
||||
std::destroy_at(getDefaultInstance());
|
||||
}
|
||||
|
||||
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE) {
|
||||
@@ -402,16 +407,10 @@ void FMaterial::terminate(FEngine& engine) {
|
||||
|
||||
destroyPrograms(engine);
|
||||
|
||||
if (mDefaultMaterialInstance) {
|
||||
mDefaultMaterialInstance->setDefaultInstance(false);
|
||||
engine.destroy(mDefaultMaterialInstance);
|
||||
mDefaultMaterialInstance = nullptr;
|
||||
}
|
||||
getDefaultInstance()->terminate(engine);
|
||||
|
||||
mPerViewDescriptorSetLayout.terminate(
|
||||
engine.getDescriptorSetLayoutFactory(), engine.getDriverApi());
|
||||
mDescriptorSetLayout.terminate(
|
||||
engine.getDescriptorSetLayoutFactory(), engine.getDriverApi());
|
||||
mPerViewDescriptorSetLayout.terminate(engine.getDriverApi());
|
||||
mDescriptorSetLayout.terminate(engine.getDriverApi());
|
||||
}
|
||||
|
||||
void FMaterial::compile(CompilerPriorityQueue priority,
|
||||
@@ -457,21 +456,7 @@ void FMaterial::compile(CompilerPriorityQueue priority,
|
||||
}
|
||||
|
||||
FMaterialInstance* FMaterial::createInstance(const char* name) const noexcept {
|
||||
if (mDefaultMaterialInstance) {
|
||||
// if we have a default instance, use it to create a new one
|
||||
return FMaterialInstance::duplicate(mDefaultMaterialInstance, name);
|
||||
} else {
|
||||
// but if we don't, just create an instance with all the default parameters
|
||||
return mEngine.createMaterialInstance(this);
|
||||
}
|
||||
}
|
||||
|
||||
FMaterialInstance* FMaterial::getDefaultInstance() noexcept {
|
||||
if (UTILS_UNLIKELY(!mDefaultMaterialInstance)) {
|
||||
mDefaultMaterialInstance = mEngine.createMaterialInstance(this);
|
||||
mDefaultMaterialInstance->setDefaultInstance(true);
|
||||
}
|
||||
return mDefaultMaterialInstance;
|
||||
return FMaterialInstance::duplicate(getDefaultInstance(), name);
|
||||
}
|
||||
|
||||
bool FMaterial::hasParameter(const char* name) const noexcept {
|
||||
@@ -594,15 +579,12 @@ Program FMaterial::getProgramWithVariants(
|
||||
|
||||
Program program;
|
||||
program.shader(ShaderStage::VERTEX, vsBuilder.data(), vsBuilder.size())
|
||||
.shader(ShaderStage::FRAGMENT, fsBuilder.data(), fsBuilder.size())
|
||||
.shaderLanguage(mMaterialParser->getShaderLanguage())
|
||||
.diagnostics(mName,
|
||||
[this, variant, vertexVariant, fragmentVariant](
|
||||
io::ostream& out) -> io::ostream& {
|
||||
return out << mName.c_str_safe() << ", variant=(" << io::hex
|
||||
<< (int)variant.key << io::dec << "), vertexVariant=(" << io::hex
|
||||
<< (int)vertexVariant.key << io::dec << "), fragmentVariant=("
|
||||
<< io::hex << (int)fragmentVariant.key << io::dec << ")";
|
||||
.shader(ShaderStage::FRAGMENT, fsBuilder.data(), fsBuilder.size())
|
||||
.shaderLanguage(mMaterialParser->getShaderLanguage())
|
||||
.diagnostics(mName,
|
||||
[this, variant](io::ostream& out) -> io::ostream& {
|
||||
return out << mName.c_str_safe()
|
||||
<< ", variant=(" << io::hex << variant.key << io::dec << ")";
|
||||
});
|
||||
|
||||
if (UTILS_UNLIKELY(mMaterialParser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
@@ -1057,13 +1039,9 @@ void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* con
|
||||
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
|
||||
assert_invariant(success);
|
||||
|
||||
mDescriptorSetLayout = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), std::move(descriptorSetLayout[0]) };
|
||||
mDescriptorSetLayout = { engine.getDriverApi(), std::move(descriptorSetLayout[0]) };
|
||||
|
||||
mPerViewDescriptorSetLayout = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), std::move(descriptorSetLayout[1]) };
|
||||
mPerViewDescriptorSetLayout = { engine.getDriverApi(), std::move(descriptorSetLayout[1]) };
|
||||
}
|
||||
|
||||
backend::descriptor_binding_t FMaterial::getSamplerBinding(
|
||||
|
||||
@@ -127,7 +127,9 @@ public:
|
||||
return const_cast<FMaterial*>(this)->getDefaultInstance();
|
||||
}
|
||||
|
||||
FMaterialInstance* getDefaultInstance() noexcept;
|
||||
FMaterialInstance* getDefaultInstance() noexcept {
|
||||
return std::launder(reinterpret_cast<FMaterialInstance*>(&mDefaultInstanceStorage));
|
||||
}
|
||||
|
||||
FEngine& getEngine() const noexcept { return mEngine; }
|
||||
|
||||
@@ -326,7 +328,8 @@ private:
|
||||
bool mSpecularAntiAliasing = false;
|
||||
|
||||
// reserve some space to construct the default material instance
|
||||
mutable FMaterialInstance* mDefaultMaterialInstance = nullptr;
|
||||
std::aligned_storage<sizeof(FMaterialInstance), alignof(FMaterialInstance)>::type mDefaultInstanceStorage;
|
||||
static_assert(sizeof(mDefaultInstanceStorage) >= sizeof(FMaterialInstance));
|
||||
|
||||
SamplerInterfaceBlock mSamplerInterfaceBlock;
|
||||
BufferInterfaceBlock mUniformInterfaceBlock;
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
@@ -65,7 +64,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material)
|
||||
mDepthWrite(false),
|
||||
mHasScissor(false),
|
||||
mIsDoubleSided(false),
|
||||
mIsDefaultInstance(false),
|
||||
mTransparencyMode(TransparencyMode::DEFAULT) {
|
||||
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
@@ -129,7 +127,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
|
||||
mDepthWrite(other->mDepthWrite),
|
||||
mHasScissor(false),
|
||||
mIsDoubleSided(other->mIsDoubleSided),
|
||||
mIsDefaultInstance(false),
|
||||
mScissorRect(other->mScissorRect),
|
||||
mName(name ? CString(name) : other->mName) {
|
||||
|
||||
@@ -202,10 +199,6 @@ void FMaterialInstance::commit(DriverApi& driver) const {
|
||||
mDescriptorSet.setSampler(binding, handle, p.params);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: eventually we should remove this in RELEASE builds
|
||||
fixMissingSamplers();
|
||||
|
||||
// Commit descriptors if needed (e.g. when textures are updated,or the first time)
|
||||
mDescriptorSet.commit(mMaterial->getDescriptorSetLayout(), driver);
|
||||
}
|
||||
@@ -325,13 +318,26 @@ const char* FMaterialInstance::getName() const noexcept {
|
||||
|
||||
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
|
||||
|
||||
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
|
||||
std::call_once(mMissingSamplersFlag, [this]() {
|
||||
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
||||
// Here we check that all declared sampler parameters are set, this is required by
|
||||
// Vulkan and Metal; GL is more permissive. If a sampler parameter is not set, we will
|
||||
// log a warning once per MaterialInstance in the system log and patch-in a dummy
|
||||
// texture.
|
||||
|
||||
auto const& layout = mMaterial->getDescriptorSetLayout();
|
||||
auto const samplersDescriptors = layout.getSamplerDescriptors();
|
||||
auto const validDescriptors = mDescriptorSet.getValidDescriptors();
|
||||
auto const missingSamplerDescriptors =
|
||||
(validDescriptors & samplersDescriptors) ^ samplersDescriptors;
|
||||
|
||||
if (UTILS_UNLIKELY(missingSamplerDescriptors.any())) {
|
||||
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
||||
std::call_once(mMissingSamplersFlag, [this, missingSamplerDescriptors, &list]() {
|
||||
|
||||
slog.w << "sampler parameters not set in MaterialInstance \""
|
||||
<< mName.c_str_safe() << "\" or Material \""
|
||||
<< mMaterial->getName().c_str_safe() << "\":\n";
|
||||
mMissingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) {
|
||||
|
||||
missingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) {
|
||||
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
||||
return item.binding == binding;
|
||||
});
|
||||
@@ -342,29 +348,8 @@ void FMaterialInstance::use(FEngine::DriverApi& driver) const {
|
||||
});
|
||||
flush(slog.w);
|
||||
});
|
||||
mMissingSamplerDescriptors.clear();
|
||||
}
|
||||
|
||||
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
}
|
||||
|
||||
void FMaterialInstance::fixMissingSamplers() const {
|
||||
// Here we check that all declared sampler parameters are set, this is required by
|
||||
// Vulkan and Metal; GL is more permissive. If a sampler parameter is not set, we will
|
||||
// log a warning once per MaterialInstance in the system log and patch-in a dummy
|
||||
// texture.
|
||||
auto const& layout = mMaterial->getDescriptorSetLayout();
|
||||
auto const samplersDescriptors = layout.getSamplerDescriptors();
|
||||
auto const validDescriptors = mDescriptorSet.getValidDescriptors();
|
||||
auto const missingSamplerDescriptors =
|
||||
(validDescriptors & samplersDescriptors) ^ samplersDescriptors;
|
||||
|
||||
// always record the missing samplers state at commit() time
|
||||
mMissingSamplerDescriptors = missingSamplerDescriptors;
|
||||
|
||||
if (UTILS_UNLIKELY(missingSamplerDescriptors.any())) {
|
||||
// here we need to set the samplers that are missing
|
||||
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
||||
missingSamplerDescriptors.forEachSetBit([this, &list](descriptor_binding_t binding) {
|
||||
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
||||
return item.binding == binding;
|
||||
@@ -395,7 +380,10 @@ void FMaterialInstance::fixMissingSamplers() const {
|
||||
}
|
||||
}
|
||||
});
|
||||
mDescriptorSet.commit(layout, driver);
|
||||
}
|
||||
|
||||
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
@@ -53,7 +52,6 @@ class FTexture;
|
||||
|
||||
class FMaterialInstance : public MaterialInstance {
|
||||
public:
|
||||
FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept;
|
||||
FMaterialInstance(FEngine& engine, FMaterialInstance const* other, const char* name);
|
||||
FMaterialInstance(const FMaterialInstance& rhs) = delete;
|
||||
FMaterialInstance& operator=(const FMaterialInstance& rhs) = delete;
|
||||
@@ -209,17 +207,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void setDefaultInstance(bool value) noexcept {
|
||||
mIsDefaultInstance = value;
|
||||
}
|
||||
|
||||
bool isDefaultInstance() const noexcept {
|
||||
return mIsDefaultInstance;
|
||||
}
|
||||
|
||||
// Called by the engine to ensure that unset samplers are initialized with placedholders.
|
||||
void fixMissingSamplers() const;
|
||||
|
||||
const char* getName() const noexcept;
|
||||
|
||||
void setParameter(std::string_view name,
|
||||
@@ -249,6 +236,9 @@ private:
|
||||
template<typename T>
|
||||
T getParameterImpl(std::string_view name) const;
|
||||
|
||||
// initialize the default instance
|
||||
FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept;
|
||||
|
||||
// keep these grouped, they're accessed together in the render-loop
|
||||
FMaterial const* mMaterial = nullptr;
|
||||
|
||||
@@ -275,7 +265,6 @@ private:
|
||||
bool mDepthWrite : 1;
|
||||
bool mHasScissor : 1;
|
||||
bool mIsDoubleSided : 1;
|
||||
bool mIsDefaultInstance : 1;
|
||||
TransparencyMode mTransparencyMode : 2;
|
||||
|
||||
uint64_t mMaterialSortingKey = 0;
|
||||
@@ -287,7 +276,6 @@ private:
|
||||
};
|
||||
|
||||
utils::CString mName;
|
||||
mutable utils::bitset64 mMissingSamplerDescriptors{};
|
||||
mutable std::once_flag mMissingSamplersFlag;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,18 +21,8 @@
|
||||
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <filament/RenderTarget.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <filament/RenderTarget.h>
|
||||
|
||||
|
||||
namespace filament {
|
||||
@@ -44,9 +34,6 @@ struct RenderTarget::BuilderDetails {
|
||||
uint32_t mWidth{};
|
||||
uint32_t mHeight{};
|
||||
uint8_t mSamples = 1; // currently not settable in the public facing API
|
||||
// The number of layers for the render target. The value should be 1 except for multiview.
|
||||
// If multiview is enabled, this value is appropriately updated based on the layerCount value
|
||||
// from each attachment. Hence, #>1 means using multiview
|
||||
uint8_t mLayerCount = 1;
|
||||
};
|
||||
|
||||
@@ -78,14 +65,6 @@ RenderTarget::Builder& RenderTarget::Builder::layer(AttachmentPoint pt, uint32_t
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderTarget::Builder& RenderTarget::Builder::multiview(AttachmentPoint pt, uint8_t layerCount,
|
||||
uint8_t baseLayer/*= 0*/) noexcept {
|
||||
mImpl->mAttachments[(size_t)pt].layer = baseLayer;
|
||||
mImpl->mAttachments[(size_t)pt].layerCount = layerCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RenderTarget* RenderTarget::Builder::build(Engine& engine) {
|
||||
using backend::TextureUsage;
|
||||
const FRenderTarget::Attachment& color = mImpl->mAttachments[(size_t)AttachmentPoint::COLOR0];
|
||||
@@ -94,15 +73,11 @@ RenderTarget* RenderTarget::Builder::build(Engine& engine) {
|
||||
if (color.texture) {
|
||||
FILAMENT_CHECK_PRECONDITION(color.texture->getUsage() & TextureUsage::COLOR_ATTACHMENT)
|
||||
<< "Texture usage must contain COLOR_ATTACHMENT";
|
||||
FILAMENT_CHECK_PRECONDITION(color.texture->getTarget() != Texture::Sampler::SAMPLER_EXTERNAL)
|
||||
<< "Color attachment can't be an external texture";
|
||||
}
|
||||
|
||||
if (depth.texture) {
|
||||
FILAMENT_CHECK_PRECONDITION(depth.texture->getUsage() & TextureUsage::DEPTH_ATTACHMENT)
|
||||
<< "Texture usage must contain DEPTH_ATTACHMENT";
|
||||
FILAMENT_CHECK_PRECONDITION(depth.texture->getTarget() != Texture::Sampler::SAMPLER_EXTERNAL)
|
||||
<< "Depth attachment can't be an external texture";
|
||||
}
|
||||
|
||||
const size_t maxDrawBuffers = downcast(engine).getDriverApi().getMaxDrawBuffers();
|
||||
@@ -116,40 +91,28 @@ RenderTarget* RenderTarget::Builder::build(Engine& engine) {
|
||||
uint32_t maxWidth = 0;
|
||||
uint32_t minHeight = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t maxHeight = 0;
|
||||
uint32_t minLayerCount = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t maxLayerCount = 0;
|
||||
uint32_t minDepth = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t maxDepth = 0;
|
||||
for (auto const& attachment : mImpl->mAttachments) {
|
||||
if (attachment.texture) {
|
||||
const uint32_t w = attachment.texture->getWidth(attachment.mipLevel);
|
||||
const uint32_t h = attachment.texture->getHeight(attachment.mipLevel);
|
||||
const uint32_t d = attachment.texture->getDepth(attachment.mipLevel);
|
||||
const uint32_t l = attachment.layerCount;
|
||||
if (l > 0) {
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
attachment.texture->getTarget() == Texture::Sampler::SAMPLER_2D_ARRAY)
|
||||
<< "Texture sampler must be of 2d array for multiview";
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(attachment.layer + l <= d)
|
||||
<< "layer + layerCount cannot exceed the number of depth";
|
||||
minWidth = std::min(minWidth, w);
|
||||
minHeight = std::min(minHeight, h);
|
||||
minLayerCount = std::min(minLayerCount, l);
|
||||
minDepth = std::min(minDepth, d);
|
||||
maxWidth = std::max(maxWidth, w);
|
||||
maxHeight = std::max(maxHeight, h);
|
||||
maxLayerCount = std::max(maxLayerCount, l);
|
||||
maxDepth = std::max(maxDepth, d);
|
||||
}
|
||||
}
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(minWidth == maxWidth && minHeight == maxHeight
|
||||
&& minLayerCount == maxLayerCount) << "All attachments dimensions must match";
|
||||
&& minDepth == maxDepth) << "All attachments dimensions must match";
|
||||
|
||||
mImpl->mWidth = minWidth;
|
||||
mImpl->mHeight = minHeight;
|
||||
if (minLayerCount > 0) {
|
||||
// mLayerCount should be 1 except for multiview use where we update this variable
|
||||
// to the number of layerCount for multiview.
|
||||
mImpl->mLayerCount = minLayerCount;
|
||||
}
|
||||
mImpl->mLayerCount = minDepth;
|
||||
return downcast(engine).createRenderTarget(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,6 @@ public:
|
||||
uint8_t mipLevel = 0;
|
||||
CubemapFace face = RenderTarget::CubemapFace::POSITIVE_X;
|
||||
uint32_t layer = 0;
|
||||
// Indicates the number of layers used for multiview, starting from the `layer` (baseIndex).
|
||||
// This means `layer` + `layerCount` cannot exceed the number of depth for the attachment.
|
||||
uint16_t layerCount = 0;
|
||||
};
|
||||
|
||||
FRenderTarget(FEngine& engine, const Builder& builder);
|
||||
|
||||
@@ -536,12 +536,6 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
renderInternal(view);
|
||||
|
||||
driver.endFrame(mFrameId);
|
||||
|
||||
// This is a workaround for internal bug b/361822355.
|
||||
// TODO: properly address the bug and remove this workaround.
|
||||
if (engine.getBackend() == backend::Backend::VULKAN) {
|
||||
engine.flushAndWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,7 +588,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
PostProcessManager& ppm = engine.getPostProcessManager();
|
||||
ppm.setFrameUniforms(driver, view.getFrameUniforms());
|
||||
ppm.setFrameUniforms(view.getFrameUniforms());
|
||||
|
||||
// DEBUG: driver commands must all happen from the same thread. Enforce that on debug builds.
|
||||
driver.debugThreading();
|
||||
@@ -1047,7 +1041,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
// (i.e. it won't be culled, unless everything is culled), so no need to complexify things.
|
||||
passBuilder.variant(variant);
|
||||
|
||||
// This is optional, if not set, the per-view descriptor-set must be set before calling execute()
|
||||
passBuilder.colorPassDescriptorSet(&view.getColorPassDescriptorSet());
|
||||
|
||||
// color-grading as subpass is done either by the color pass or the TAA pass if any
|
||||
|
||||
@@ -200,7 +200,7 @@ void updateDataAt(backend::DriverApi& driver,
|
||||
size_t const elementSize = sizeof(float2);
|
||||
size_t const size = getSkinningBufferSize(count);
|
||||
auto* out = (float2*)malloc(size);
|
||||
memcpy(out, pairs.begin(), size);
|
||||
std::memcpy(out, pairs.begin(), size);
|
||||
|
||||
size_t const textureWidth = getSkinningBufferWidth(count);
|
||||
size_t const lineCount = count / textureWidth;
|
||||
|
||||
@@ -233,15 +233,14 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) {
|
||||
mSwizzle = builder->mSwizzle;
|
||||
mTextureIsSwizzled = builder->mTextureIsSwizzled;
|
||||
|
||||
bool const isImported = builder->mImportedId != 0;
|
||||
if (mTarget == SamplerType::SAMPLER_EXTERNAL && !isImported) {
|
||||
if (mTarget == SamplerType::SAMPLER_EXTERNAL) {
|
||||
// mHandle and mHandleForSampling will be created in setExternalImage()
|
||||
// If this Texture is used for sampling before setExternalImage() is called,
|
||||
// we'll lazily create a 1x1 placeholder texture.
|
||||
return;
|
||||
}
|
||||
|
||||
if (UTILS_LIKELY(!isImported)) {
|
||||
if (UTILS_LIKELY(builder->mImportedId == 0)) {
|
||||
mHandle = driver.createTexture(
|
||||
mTarget, mLevelCount, mFormat, mSampleCount, mWidth, mHeight, mDepth, mUsage);
|
||||
} else {
|
||||
@@ -486,29 +485,15 @@ void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noex
|
||||
}
|
||||
|
||||
void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept {
|
||||
if (mTarget != Sampler::SAMPLER_EXTERNAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& api = engine.getDriverApi();
|
||||
auto texture = api.createTexture(
|
||||
mTarget, mLevelCount, mFormat, mSampleCount, mWidth, mHeight, mDepth, mUsage);
|
||||
|
||||
if (mTextureIsSwizzled) {
|
||||
auto const& s = mSwizzle;
|
||||
auto swizzleView = api.createTextureViewSwizzle(texture, s[0], s[1], s[2], s[3]);
|
||||
api.destroyTexture(texture);
|
||||
texture = swizzleView;
|
||||
}
|
||||
|
||||
setHandles(texture);
|
||||
|
||||
if (stream) {
|
||||
FILAMENT_CHECK_PRECONDITION(mTarget == Sampler::SAMPLER_EXTERNAL)
|
||||
<< "Texture target must be SAMPLER_EXTERNAL";
|
||||
|
||||
mStream = stream;
|
||||
api.setExternalStream(mHandle, stream->getHandle());
|
||||
engine.getDriverApi().setExternalStream(mHandle, stream->getHandle());
|
||||
} else {
|
||||
mStream = nullptr;
|
||||
api.setExternalStream(mHandle, backend::Handle<backend::HwStream>());
|
||||
engine.getDriverApi().setExternalStream(mHandle, backend::Handle<backend::HwStream>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,6 +534,10 @@ void FTexture::updateLodRange(uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||
range.first = std::min(range.first, baseLevel);
|
||||
range.last = std::max(range.last, last);
|
||||
}
|
||||
if (range.first == 0 && range.last == mLevelCount) {
|
||||
// the whole range lod range is used, we don't need the view anymore
|
||||
range.first = range.last = 0;
|
||||
}
|
||||
// We defer the creation of the texture view to getHwHandleForSampling() because it
|
||||
// is a common case that by then, the view won't be needed. Creating the first view on a
|
||||
// texture has a backend cost.
|
||||
@@ -593,15 +582,16 @@ backend::Handle<backend::HwTexture> FTexture::getHwHandleForSampling() const noe
|
||||
if (UTILS_UNLIKELY(mTarget == SamplerType::SAMPLER_EXTERNAL && !mHandleForSampling)) {
|
||||
return setHandleForSampling(createPlaceholderTexture(*mDriver));
|
||||
}
|
||||
|
||||
auto const& range = mLodRange;
|
||||
auto& activeRange = mActiveLodRange;
|
||||
bool const lodRangeChanged = activeRange.first != range.first || activeRange.last != range.last;
|
||||
if (UTILS_UNLIKELY(lodRangeChanged)) {
|
||||
if (UTILS_UNLIKELY(activeRange.first != range.first || activeRange.last != range.last)) {
|
||||
activeRange = range;
|
||||
if (range.empty() || hasAllLods(range)) {
|
||||
if (range.empty()) {
|
||||
setHandleForSampling(mHandle);
|
||||
} else {
|
||||
setHandleForSampling(mDriver->createTextureView(mHandle, range.first, range.size()));
|
||||
setHandleForSampling(
|
||||
mDriver->createTextureView(mHandle, range.first, range.last - range.first));
|
||||
}
|
||||
}
|
||||
return mHandleForSampling;
|
||||
|
||||
@@ -130,13 +130,7 @@ private:
|
||||
uint8_t first = 0; // first lod
|
||||
uint8_t last = 0; // 1 past last lod
|
||||
bool empty() const noexcept { return first == last; }
|
||||
size_t size() const noexcept { return last - first; }
|
||||
};
|
||||
|
||||
bool hasAllLods(LodRange const range) const noexcept {
|
||||
return range.first == 0 && range.last == mLevelCount;
|
||||
}
|
||||
|
||||
void updateLodRange(uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||
void setHandles(backend::Handle<backend::HwTexture> handle) noexcept;
|
||||
backend::Handle<backend::HwTexture> setHandleForSampling(
|
||||
|
||||
@@ -142,7 +142,7 @@ void FView::terminate(FEngine& engine) {
|
||||
|
||||
ShadowMapManager::terminate(engine, mShadowMapManager);
|
||||
mUniforms.terminate(driver);
|
||||
mColorPassDescriptorSet.terminate(engine.getDescriptorSetLayoutFactory(), driver);
|
||||
mColorPassDescriptorSet.terminate(driver);
|
||||
mFroxelizer.terminate(driver);
|
||||
mCommonRenderableDescriptorSet.terminate(driver);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ColorPassDescriptorSet.h"
|
||||
|
||||
#include "Froxelizer.h"
|
||||
#include "HwDescriptorSetLayoutFactory.h"
|
||||
#include "ShadowMapManager.h"
|
||||
#include "TypedUniformBuffer.h"
|
||||
|
||||
@@ -101,7 +100,6 @@ ColorPassDescriptorSet::ColorPassDescriptorSet(FEngine& engine,
|
||||
for (bool const fog: { false, true }) {
|
||||
auto index = ColorPassDescriptorSet::getIndex(lit, ssr, fog);
|
||||
mDescriptorSetLayout[index] = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(),
|
||||
descriptor_sets::getPerViewDescriptorSetLayout(
|
||||
MaterialDomain::SURFACE,
|
||||
@@ -139,12 +137,12 @@ void ColorPassDescriptorSet::init(
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::terminate(HwDescriptorSetLayoutFactory& factory, DriverApi& driver) {
|
||||
void ColorPassDescriptorSet::terminate(DriverApi& driver) {
|
||||
for (auto&& entry : mDescriptorSet) {
|
||||
entry.terminate(driver);
|
||||
}
|
||||
for (auto&& entry : mDescriptorSetLayout) {
|
||||
entry.terminate(factory, driver);
|
||||
entry.terminate(driver);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
namespace filament {
|
||||
|
||||
class DescriptorSetLayout;
|
||||
class HwDescriptorSetLayoutFactory;
|
||||
|
||||
struct AmbientOcclusionOptions;
|
||||
struct DynamicResolutionOptions;
|
||||
@@ -89,7 +88,7 @@ public:
|
||||
backend::BufferObjectHandle recordBuffer,
|
||||
backend::BufferObjectHandle froxelBuffer) noexcept;
|
||||
|
||||
void terminate(HwDescriptorSetLayoutFactory& factory, backend::DriverApi& driver);
|
||||
void terminate(backend::DriverApi& driver);
|
||||
|
||||
void prepareCamera(FEngine& engine, const CameraInfo& camera) noexcept;
|
||||
void prepareLodBias(float bias, math::float2 derivativesScale) noexcept;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
@@ -45,8 +44,7 @@ DescriptorSet::~DescriptorSet() noexcept {
|
||||
|
||||
DescriptorSet::DescriptorSet(DescriptorSetLayout const& descriptorSetLayout) noexcept
|
||||
: mDescriptors(descriptorSetLayout.getMaxDescriptorBinding() + 1),
|
||||
mDirty(std::numeric_limits<uint64_t>::max()),
|
||||
mSetAfterCommitWarning(false) {
|
||||
mDirty(std::numeric_limits<uint64_t>::max()) {
|
||||
}
|
||||
|
||||
DescriptorSet::DescriptorSet(DescriptorSet&& rhs) noexcept = default;
|
||||
@@ -59,7 +57,6 @@ DescriptorSet& DescriptorSet::operator=(DescriptorSet&& rhs) noexcept {
|
||||
mDescriptorSetHandle = std::move(rhs.mDescriptorSetHandle);
|
||||
mDirty = rhs.mDirty;
|
||||
mValid = rhs.mValid;
|
||||
mSetAfterCommitWarning = rhs.mSetAfterCommitWarning;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -106,21 +103,8 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
|
||||
void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints set,
|
||||
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept {
|
||||
// TODO: on debug check that dynamicOffsets is large enough
|
||||
|
||||
assert_invariant(mDirty.none());
|
||||
assert_invariant(mDescriptorSetHandle);
|
||||
|
||||
// TODO: Make sure clients do the right thing and not change material instance parameters
|
||||
// within the renderpass. We have to comment the assert out since it crashed a client's debug
|
||||
// build.
|
||||
// assert_invariant(mDirty.none());
|
||||
if (mDirty.any() && !mSetAfterCommitWarning) {
|
||||
mDirty.forEachSetBit([&](uint8_t binding) {
|
||||
utils::slog.w << "Descriptor set (handle=" << mDescriptorSetHandle.getId()
|
||||
<< ") binding=" << (int) binding
|
||||
<< " was set between begin/endRenderPass" << utils::io::endl;
|
||||
});
|
||||
mSetAfterCommitWarning = true;
|
||||
}
|
||||
driver.bindDescriptorSet(mDescriptorSetHandle, +set, std::move(dynamicOffsets));
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ private:
|
||||
mutable utils::bitset64 mDirty; // 8
|
||||
mutable utils::bitset64 mValid; // 8
|
||||
backend::DescriptorSetHandle mDescriptorSetHandle; // 4
|
||||
mutable bool mSetAfterCommitWarning = false; // 1
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "DescriptorSetLayout.h"
|
||||
|
||||
#include "HwDescriptorSetLayoutFactory.h"
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -29,9 +27,7 @@ namespace filament {
|
||||
|
||||
DescriptorSetLayout::DescriptorSetLayout() noexcept = default;
|
||||
|
||||
DescriptorSetLayout::DescriptorSetLayout(
|
||||
HwDescriptorSetLayoutFactory& factory,
|
||||
backend::DriverApi& driver,
|
||||
DescriptorSetLayout::DescriptorSetLayout(backend::DriverApi& driver,
|
||||
backend::DescriptorSetLayout descriptorSetLayout) noexcept {
|
||||
for (auto&& desc : descriptorSetLayout.bindings) {
|
||||
mMaxDescriptorBinding = std::max(mMaxDescriptorBinding, desc.binding);
|
||||
@@ -39,15 +35,13 @@ DescriptorSetLayout::DescriptorSetLayout(
|
||||
mUniformBuffers.set(desc.binding, desc.type == backend::DescriptorType::UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
mDescriptorSetLayoutHandle = factory.create(driver,
|
||||
mDescriptorSetLayoutHandle = driver.createDescriptorSetLayout(
|
||||
std::move(descriptorSetLayout));
|
||||
}
|
||||
|
||||
void DescriptorSetLayout::terminate(
|
||||
HwDescriptorSetLayoutFactory& factory,
|
||||
backend::DriverApi& driver) noexcept {
|
||||
void DescriptorSetLayout::terminate(backend::DriverApi& driver) noexcept {
|
||||
if (mDescriptorSetLayoutHandle) {
|
||||
factory.destroy(driver, mDescriptorSetLayoutHandle);
|
||||
driver.destroyDescriptorSetLayout(mDescriptorSetLayoutHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,14 +29,10 @@
|
||||
|
||||
namespace filament {
|
||||
|
||||
class HwDescriptorSetLayoutFactory;
|
||||
|
||||
class DescriptorSetLayout {
|
||||
public:
|
||||
DescriptorSetLayout() noexcept;
|
||||
DescriptorSetLayout(
|
||||
HwDescriptorSetLayoutFactory& factory,
|
||||
backend::DriverApi& driver,
|
||||
DescriptorSetLayout(backend::DriverApi& driver,
|
||||
backend::DescriptorSetLayout descriptorSetLayout) noexcept;
|
||||
|
||||
DescriptorSetLayout(DescriptorSetLayout const&) = delete;
|
||||
@@ -44,9 +40,7 @@ public:
|
||||
DescriptorSetLayout& operator=(DescriptorSetLayout const&) = delete;
|
||||
DescriptorSetLayout& operator=(DescriptorSetLayout&& rhs) noexcept;
|
||||
|
||||
void terminate(
|
||||
HwDescriptorSetLayoutFactory& factory,
|
||||
backend::DriverApi& driver) noexcept;
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
backend::DescriptorSetLayoutHandle getHandle() const noexcept {
|
||||
return mDescriptorSetLayoutHandle;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "PostProcessDescriptorSet.h"
|
||||
|
||||
#include "HwDescriptorSetLayoutFactory.h"
|
||||
#include "TypedUniformBuffer.h"
|
||||
|
||||
#include "details/Engine.h"
|
||||
@@ -38,16 +37,15 @@ void PostProcessDescriptorSet::init(FEngine& engine) noexcept {
|
||||
|
||||
// create the descriptor-set layout
|
||||
mDescriptorSetLayout = filament::DescriptorSetLayout{
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), descriptor_sets::getPostProcessLayout() };
|
||||
|
||||
// create the descriptor-set from the layout
|
||||
mDescriptorSet = DescriptorSet{ mDescriptorSetLayout };
|
||||
}
|
||||
|
||||
void PostProcessDescriptorSet::terminate(HwDescriptorSetLayoutFactory& factory, DriverApi& driver) {
|
||||
void PostProcessDescriptorSet::terminate(DriverApi& driver) {
|
||||
mDescriptorSet.terminate(driver);
|
||||
mDescriptorSetLayout.terminate(factory, driver);
|
||||
mDescriptorSetLayout.terminate(driver);
|
||||
}
|
||||
|
||||
void PostProcessDescriptorSet::setFrameUniforms(DriverApi& driver,
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
namespace filament {
|
||||
|
||||
class FEngine;
|
||||
class HwDescriptorSetLayoutFactory;
|
||||
|
||||
class PostProcessDescriptorSet {
|
||||
public:
|
||||
@@ -38,7 +37,7 @@ public:
|
||||
|
||||
void init(FEngine& engine) noexcept;
|
||||
|
||||
void terminate(HwDescriptorSetLayoutFactory& factory, backend::DriverApi& driver);
|
||||
void terminate(backend::DriverApi& driver);
|
||||
|
||||
void setFrameUniforms(backend::DriverApi& driver,
|
||||
TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
|
||||
|
||||
@@ -42,15 +42,10 @@ SsrPassDescriptorSet::SsrPassDescriptorSet() noexcept = default;
|
||||
void SsrPassDescriptorSet::init(FEngine& engine) noexcept {
|
||||
// create the descriptor-set from the layout
|
||||
mDescriptorSet = DescriptorSet{ engine.getPerViewDescriptorSetLayoutSsrVariant() };
|
||||
|
||||
// create a dummy Shadow UBO (see comment in setFrameUniforms() below)
|
||||
mShadowUbh = engine.getDriverApi().createBufferObject(sizeof(ShadowUib),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
}
|
||||
|
||||
void SsrPassDescriptorSet::terminate(DriverApi& driver) {
|
||||
mDescriptorSet.terminate(driver);
|
||||
driver.destroyBufferObject(mShadowUbh);
|
||||
}
|
||||
|
||||
void SsrPassDescriptorSet::setFrameUniforms(TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
|
||||
@@ -58,11 +53,6 @@ void SsrPassDescriptorSet::setFrameUniforms(TypedUniformBuffer<PerViewUib>& unif
|
||||
mDescriptorSet.setBuffer(+PerViewBindingPoints::FRAME_UNIFORMS,
|
||||
uniforms.getUboHandle(), 0, uniforms.getSize());
|
||||
|
||||
// This is actually not used for the SSR variants, but the descriptor-set layout needs
|
||||
// to have this UBO because the fragment shader used is the "generic" one. Both Metal
|
||||
// and GL would be okay without this, but Vulkan's validation layer would complain.
|
||||
mDescriptorSet.setBuffer(+PerViewBindingPoints::SHADOWS, mShadowUbh, 0, sizeof(ShadowUib));
|
||||
|
||||
mUniforms = std::addressof(uniforms);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ public:
|
||||
private:
|
||||
TypedUniformBuffer<PerViewUib>* mUniforms = nullptr;
|
||||
DescriptorSet mDescriptorSet;
|
||||
backend::BufferObjectHandle mShadowUbh;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.55.0"
|
||||
spec.version = "1.54.2"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.55.0/filament-v1.55.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.54.2/filament-v1.54.2-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 55;
|
||||
static constexpr size_t MATERIAL_VERSION = 54;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -45,16 +45,16 @@ enum class DescriptorSetBindingPoints : uint8_t {
|
||||
// binding point for the "per-view" descriptor set
|
||||
enum class PerViewBindingPoints : uint8_t {
|
||||
FRAME_UNIFORMS = 0, // uniforms updated per view
|
||||
SHADOWS = 1, // punctual shadow data
|
||||
LIGHTS = 2, // lights data array
|
||||
LIGHTS = 1, // lights data array
|
||||
SHADOWS = 2, // punctual shadow data
|
||||
RECORD_BUFFER = 3, // froxel record buffer
|
||||
FROXEL_BUFFER = 4, // froxel buffer
|
||||
STRUCTURE = 5, // variable, DEPTH
|
||||
SHADOW_MAP = 6, // user defined (1024x1024) DEPTH, array
|
||||
IBL_DFG_LUT = 7, // user defined (128x128), RGB16F
|
||||
IBL_SPECULAR = 8, // user defined, user defined, CUBEMAP
|
||||
SSAO = 9, // variable, RGB8 {AO, [depth]}
|
||||
SSR = 10, // variable, RGB_11_11_10, mipmapped
|
||||
SHADOW_MAP = 5, // user defined (1024x1024) DEPTH, array
|
||||
IBL_DFG_LUT = 6, // user defined (128x128), RGB16F
|
||||
IBL_SPECULAR = 7, // user defined, user defined, CUBEMAP
|
||||
SSAO = 8, // variable, RGB8 {AO, [depth]}
|
||||
SSR = 9, // variable, RGB_11_11_10, mipmapped
|
||||
STRUCTURE = 10, // variable, DEPTH
|
||||
FOG = 11 // variable, user defined, CUBEMAP
|
||||
};
|
||||
|
||||
|
||||
@@ -26,55 +26,69 @@
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
|
||||
namespace filament::descriptor_sets {
|
||||
|
||||
using namespace backend;
|
||||
|
||||
static DescriptorSetLayout const postProcessDescriptorSetLayout{{
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||
}};
|
||||
static DescriptorSetLayout const postProcessDescriptorSetLayout{
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||
+PerViewBindingPoints::FRAME_UNIFORMS,
|
||||
DescriptorFlags::NONE, 0 },
|
||||
}};
|
||||
|
||||
static DescriptorSetLayout const depthVariantDescriptorSetLayout{{
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||
}};
|
||||
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||
+PerViewBindingPoints::FRAME_UNIFORMS,
|
||||
DescriptorFlags::NONE, 0 },
|
||||
}};
|
||||
|
||||
// ssrVariantDescriptorSetLayout must match perViewDescriptorSetLayout's vertex stage. This is
|
||||
// because the SSR variant is always using the "standard" vertex shader (i.e. there is no
|
||||
// dedicated SSR vertex shader), which uses perViewDescriptorSetLayout.
|
||||
// This means that PerViewBindingPoints::SHADOWS must be in the layout even though it's not used
|
||||
// by the SSR variant.
|
||||
static DescriptorSetLayout const ssrVariantDescriptorSetLayout{{
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
|
||||
}};
|
||||
static DescriptorSetLayout const ssrVariantDescriptorSetLayout{
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||
+PerViewBindingPoints::FRAME_UNIFORMS,
|
||||
DescriptorFlags::NONE, 0 },
|
||||
{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::FRAGMENT,
|
||||
+PerViewBindingPoints::SSR,
|
||||
DescriptorFlags::NONE, 0 },
|
||||
{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::FRAGMENT,
|
||||
+PerViewBindingPoints::STRUCTURE,
|
||||
DescriptorFlags::NONE, 0 },
|
||||
}};
|
||||
|
||||
static DescriptorSetLayout perViewDescriptorSetLayout = {{
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::LIGHTS },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::RECORD_BUFFER },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FROXEL_BUFFER },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOW_MAP },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_DFG_LUT },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_SPECULAR },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSAO },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::LIGHTS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::RECORD_BUFFER, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FROXEL_BUFFER, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOW_MAP, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSAO, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_DFG_LUT, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_SPECULAR, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG, DescriptorFlags::NONE, 0 },
|
||||
}};
|
||||
|
||||
|
||||
static DescriptorSetLayout perRenderableDescriptorSetLayout = {{
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_POSITIONS },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_TANGENTS },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET, 0 },
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_POSITIONS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_TANGENTS, DescriptorFlags::NONE, 0 },
|
||||
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, DescriptorFlags::NONE, 0 },
|
||||
}};
|
||||
|
||||
DescriptorSetLayout const& getPostProcessLayout() noexcept {
|
||||
@@ -96,41 +110,39 @@ DescriptorSetLayout const& getPerRenderableLayout() noexcept {
|
||||
utils::CString getDescriptorName(DescriptorSetBindingPoints set,
|
||||
descriptor_binding_t binding) noexcept {
|
||||
using namespace std::literals;
|
||||
|
||||
static std::unordered_map<descriptor_binding_t, std::string_view> const set0{{
|
||||
{ +PerViewBindingPoints::FRAME_UNIFORMS, "FrameUniforms"sv },
|
||||
{ +PerViewBindingPoints::SHADOWS, "ShadowUniforms"sv },
|
||||
{ +PerViewBindingPoints::LIGHTS, "LightsUniforms"sv },
|
||||
{ +PerViewBindingPoints::RECORD_BUFFER, "FroxelRecordUniforms"sv },
|
||||
{ +PerViewBindingPoints::FROXEL_BUFFER, "FroxelsUniforms"sv },
|
||||
{ +PerViewBindingPoints::STRUCTURE, "sampler0_structure"sv },
|
||||
{ +PerViewBindingPoints::SHADOW_MAP, "sampler0_shadowMap"sv },
|
||||
{ +PerViewBindingPoints::IBL_DFG_LUT, "sampler0_iblDFG"sv },
|
||||
{ +PerViewBindingPoints::IBL_SPECULAR, "sampler0_iblSpecular"sv },
|
||||
{ +PerViewBindingPoints::SSAO, "sampler0_ssao"sv },
|
||||
{ +PerViewBindingPoints::SSR, "sampler0_ssr"sv },
|
||||
{ +PerViewBindingPoints::FOG, "sampler0_fog"sv },
|
||||
}};
|
||||
|
||||
static std::unordered_map<descriptor_binding_t, std::string_view> const set1{{
|
||||
{ +PerRenderableBindingPoints::OBJECT_UNIFORMS, "ObjectUniforms"sv },
|
||||
{ +PerRenderableBindingPoints::BONES_UNIFORMS, "BonesUniforms"sv },
|
||||
{ +PerRenderableBindingPoints::MORPHING_UNIFORMS, "MorphingUniforms"sv },
|
||||
{ +PerRenderableBindingPoints::MORPH_TARGET_POSITIONS, "sampler1_positions"sv },
|
||||
{ +PerRenderableBindingPoints::MORPH_TARGET_TANGENTS, "sampler1_tangents"sv },
|
||||
{ +PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, "sampler1_indicesAndWeights"sv },
|
||||
}};
|
||||
constexpr const std::string_view set0[] = {
|
||||
"FrameUniforms"sv,
|
||||
"LightsUniforms"sv,
|
||||
"ShadowUniforms"sv,
|
||||
"FroxelRecordUniforms"sv,
|
||||
"FroxelsUniforms"sv,
|
||||
"sampler0_shadowMap"sv,
|
||||
"sampler0_iblDFG"sv,
|
||||
"sampler0_iblSpecular"sv,
|
||||
"sampler0_ssao"sv,
|
||||
"sampler0_ssr"sv,
|
||||
"sampler0_structure"sv,
|
||||
"sampler0_fog"sv,
|
||||
};
|
||||
constexpr const std::string_view set1[] = {
|
||||
"ObjectUniforms"sv,
|
||||
"BonesUniforms"sv,
|
||||
"MorphingUniforms"sv,
|
||||
"sampler1_positions"sv,
|
||||
"sampler1_tangents"sv,
|
||||
"sampler1_indicesAndWeights"sv,
|
||||
};
|
||||
|
||||
switch (set) {
|
||||
case DescriptorSetBindingPoints::PER_VIEW: {
|
||||
auto pos = set0.find(binding);
|
||||
assert_invariant(pos != set0.end());
|
||||
return { pos->second.data(), pos->second.size() };
|
||||
assert_invariant(binding < perViewDescriptorSetLayout.bindings.size());
|
||||
std::string_view const& s = set0[binding];
|
||||
return { s.data(), s.size() };
|
||||
}
|
||||
case DescriptorSetBindingPoints::PER_RENDERABLE: {
|
||||
auto pos = set1.find(binding);
|
||||
assert_invariant(pos != set1.end());
|
||||
return { pos->second.data(), pos->second.size() };
|
||||
assert_invariant(binding < perRenderableDescriptorSetLayout.bindings.size());
|
||||
std::string_view const& s = set1[binding];
|
||||
return { s.data(), s.size() };
|
||||
}
|
||||
case DescriptorSetBindingPoints::PER_MATERIAL: {
|
||||
assert_invariant(binding < 1);
|
||||
|
||||
@@ -157,9 +157,7 @@ static void collectDescriptorsForSet(filament::DescriptorSetBindingPoints set,
|
||||
return descriptor_sets::getSsrVariantLayout();
|
||||
}
|
||||
return descriptor_sets::getPerViewDescriptorSetLayout(config.domain,
|
||||
config.variantFilter,
|
||||
material.isLit || material.hasShadowMultiplier,
|
||||
material.reflectionMode,
|
||||
config.variantFilter, material.isLit, material.reflectionMode,
|
||||
material.refractionMode);
|
||||
}
|
||||
case DescriptorSetBindingPoints::PER_RENDERABLE:
|
||||
|
||||
@@ -952,7 +952,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
|
||||
// Write the variant to a file.
|
||||
if (mSaveRawVariants) {
|
||||
int const variantKey = v.variant.key;
|
||||
int variantKey = v.variant.key;
|
||||
auto getExtension = [](backend::ShaderStage stage) {
|
||||
switch (stage) {
|
||||
case backend::ShaderStage::VERTEX:
|
||||
@@ -1551,7 +1551,7 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
|
||||
backend::DescriptorSetLayout const perViewDescriptorSetLayout =
|
||||
descriptor_sets::getPerViewDescriptorSetLayout(
|
||||
mMaterialDomain, mVariantFilter,
|
||||
info.isLit || info.hasShadowMultiplier, info.reflectionMode, info.refractionMode);
|
||||
info.isLit, info.reflectionMode, info.refractionMode);
|
||||
|
||||
// Descriptor layout and descriptor name/binding mapping
|
||||
container.push<MaterialDescriptorBindingsChuck>(info.sib, perViewDescriptorSetLayout);
|
||||
|
||||
@@ -16,24 +16,7 @@
|
||||
|
||||
#include "MaterialVariants.h"
|
||||
|
||||
#include "shaders/ShaderGenerator.h"
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filamat {
|
||||
|
||||
@@ -53,67 +36,13 @@ std::vector<Variant> determineSurfaceVariants(
|
||||
filteredVariant = filament::Variant::filterVariant(
|
||||
filteredVariant, isLit || shadowMultiplier);
|
||||
|
||||
auto const vertexVariant = filament::Variant::filterVariantVertex(filteredVariant);
|
||||
if (vertexVariant == variant) {
|
||||
if (filament::Variant::filterVariantVertex(filteredVariant) == variant) {
|
||||
variants.emplace_back(variant, filament::backend::ShaderStage::VERTEX);
|
||||
}
|
||||
|
||||
auto const fragmentVariant = filament::Variant::filterVariantFragment(filteredVariant);
|
||||
if (fragmentVariant == variant) {
|
||||
if (filament::Variant::filterVariantFragment(filteredVariant) == variant) {
|
||||
variants.emplace_back(variant, filament::backend::ShaderStage::FRAGMENT);
|
||||
}
|
||||
|
||||
// Here we make sure that the combination of vertex and fragment variants have compatible
|
||||
// PER_VIEW descriptor-set layouts. This could actually be a static/compile-time check
|
||||
// because it is entirely decided in DescriptorSets.cpp. Unfortunately it's not possible
|
||||
// to write this entirely as a constexpr.
|
||||
|
||||
if (UTILS_UNLIKELY(vertexVariant != fragmentVariant)) {
|
||||
// fragment and vertex variants are different, we need to check the layouts are
|
||||
// compatible.
|
||||
using filament::ReflectionMode;
|
||||
using filament::RefractionMode;
|
||||
using filament::backend::ShaderStage;
|
||||
|
||||
// And we need to do that for all configurations of the "PER_VIEW" descriptor set
|
||||
// layouts (there are eight).
|
||||
// See ShaderGenerator::getPerViewDescriptorSetLayoutWithVariant.
|
||||
for (auto reflection: {
|
||||
ReflectionMode::SCREEN_SPACE,
|
||||
ReflectionMode::DEFAULT }) {
|
||||
for (auto refraction: {
|
||||
RefractionMode::SCREEN_SPACE,
|
||||
RefractionMode::CUBEMAP,
|
||||
RefractionMode::NONE }) {
|
||||
auto const vdsl = ShaderGenerator::getPerViewDescriptorSetLayoutWithVariant(
|
||||
vertexVariant, userVariantFilter, isLit || shadowMultiplier,
|
||||
reflection, refraction);
|
||||
auto const fdsl = ShaderGenerator::getPerViewDescriptorSetLayoutWithVariant(
|
||||
fragmentVariant, userVariantFilter, isLit || shadowMultiplier,
|
||||
reflection, refraction);
|
||||
// Check that all bindings present in the vertex shader DescriptorSetLayout
|
||||
// are also present in the fragment shader DescriptorSetLayout.
|
||||
for (auto const& r: vdsl.bindings) {
|
||||
if (!hasShaderType(r.stageFlags, ShaderStage::VERTEX)) {
|
||||
// ignore descriptors that are of the fragment stage only
|
||||
continue;
|
||||
}
|
||||
auto const pos = std::find_if(fdsl.bindings.begin(), fdsl.bindings.end(),
|
||||
[r](auto const& l) {
|
||||
return l.count == r.count && l.type == r.type &&
|
||||
l.binding == r.binding && l.flags == r.flags &&
|
||||
l.stageFlags == r.stageFlags;
|
||||
});
|
||||
|
||||
// A mismatch is fatal. The material is ill-formed. This typically
|
||||
// mean a bug / inconsistency in DescriptorsSets.cpp
|
||||
FILAMENT_CHECK_POSTCONDITION(pos != fdsl.bindings.end())
|
||||
<< "Variant " << +k << " has mismatched descriptorset layouts";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
@@ -606,10 +606,28 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
|
||||
if (featureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
|
||||
|
||||
auto getPerViewDescriptorSetLayoutWithVariant = [](
|
||||
filament::Variant variant,
|
||||
UserVariantFilterMask variantFilter,
|
||||
bool isLit,
|
||||
ReflectionMode reflectionMode,
|
||||
RefractionMode refractionMode) -> backend::DescriptorSetLayout {
|
||||
|
||||
if (filament::Variant::isValidDepthVariant(variant)) {
|
||||
return descriptor_sets::getDepthVariantLayout();
|
||||
}
|
||||
if (filament::Variant::isSSRVariant(variant)) {
|
||||
return descriptor_sets::getSsrVariantLayout();
|
||||
}
|
||||
// We need to filter out all the descriptors not included in the "resolved" layout below
|
||||
return descriptor_sets::getPerViewDescriptorSetLayout(
|
||||
MaterialDomain::SURFACE, variantFilter,
|
||||
isLit, reflectionMode, refractionMode);
|
||||
};
|
||||
|
||||
auto const perViewDescriptorSetLayout = getPerViewDescriptorSetLayoutWithVariant(
|
||||
variant, variantFilter,
|
||||
material.isLit || material.hasShadowMultiplier,
|
||||
material.reflectionMode, material.refractionMode);
|
||||
material.isLit, material.reflectionMode, material.refractionMode);
|
||||
|
||||
// this is the list of samplers we need to filter
|
||||
auto list = SibGenerator::getPerViewSib(variant).getSamplerInfoList();
|
||||
@@ -839,22 +857,4 @@ bool ShaderGenerator::hasStereo(
|
||||
&& featureLevel > MaterialBuilder::FeatureLevel::FEATURE_LEVEL_0;
|
||||
}
|
||||
|
||||
backend::DescriptorSetLayout ShaderGenerator::getPerViewDescriptorSetLayoutWithVariant(
|
||||
filament::Variant variant,
|
||||
UserVariantFilterMask variantFilter,
|
||||
bool isLit,
|
||||
ReflectionMode reflectionMode,
|
||||
RefractionMode refractionMode) {
|
||||
if (filament::Variant::isValidDepthVariant(variant)) {
|
||||
return descriptor_sets::getDepthVariantLayout();
|
||||
}
|
||||
if (filament::Variant::isSSRVariant(variant)) {
|
||||
return descriptor_sets::getSsrVariantLayout();
|
||||
}
|
||||
// We need to filter out all the descriptors not included in the "resolved" layout below
|
||||
return descriptor_sets::getPerViewDescriptorSetLayout(
|
||||
MaterialDomain::SURFACE, variantFilter,
|
||||
isLit, reflectionMode, refractionMode);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -88,13 +88,6 @@ public:
|
||||
MaterialBuilder::FeatureLevel featureLevel,
|
||||
MaterialInfo const& material) noexcept;
|
||||
|
||||
static filament::backend::DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
|
||||
filament::Variant variant,
|
||||
filament::UserVariantFilterMask variantFilter,
|
||||
bool isLit,
|
||||
filament::ReflectionMode reflectionMode,
|
||||
filament::RefractionMode refractionMode);
|
||||
|
||||
private:
|
||||
static void generateVertexDomainDefines(utils::io::sstream& out,
|
||||
filament::VertexDomain domain) noexcept;
|
||||
|
||||
@@ -47,7 +47,6 @@ set(LIBS
|
||||
geometry
|
||||
getopt
|
||||
image
|
||||
imageio
|
||||
imgui
|
||||
ktxreader
|
||||
math
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <math/vec3.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace filament {
|
||||
class Engine;
|
||||
|
||||
@@ -552,9 +552,6 @@ void FilamentApp::loadIBL(std::string_view path) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that IBL holds a skybox, and Scene also holds a reference. We cannot release IBL's
|
||||
// skybox until after new skybox has been set in the scene.
|
||||
std::unique_ptr<IBL> oldIBL = std::move(mIBL);
|
||||
mIBL = std::make_unique<IBL>(*mEngine);
|
||||
|
||||
if (!iblPath.isDirectory()) {
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
#include <ktxreader/Ktx1Reader.h>
|
||||
|
||||
#include <imageio/ImageDecoder.h>
|
||||
|
||||
#include <filament-iblprefilter/IBLPrefilterContext.h>
|
||||
|
||||
#include <stb_image.h>
|
||||
@@ -39,8 +37,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace ktxreader;
|
||||
@@ -64,51 +60,26 @@ bool IBL::loadFromEquirect(Path const& path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int w = 0, h = 0;
|
||||
int n = 0;
|
||||
size_t size = 0;
|
||||
void* data = nullptr;
|
||||
void* user = nullptr;
|
||||
Texture::PixelBufferDescriptor::Callback destroyer{};
|
||||
|
||||
if (path.getExtension() == "exr") {
|
||||
std::ifstream in_stream(path.getAbsolutePath().c_str(), std::ios::binary);
|
||||
image::LinearImage* image = new image::LinearImage(
|
||||
image::ImageDecoder::decode(in_stream, path.getAbsolutePath().c_str()));
|
||||
w = image->getWidth();
|
||||
h = image->getHeight();
|
||||
n = image->getChannels();
|
||||
size = w * h * n * sizeof(float);
|
||||
data = image->getPixelRef();
|
||||
user = image;
|
||||
destroyer = [](void*, size_t, void* user) {
|
||||
delete reinterpret_cast<image::LinearImage*>(user);
|
||||
};
|
||||
} else {
|
||||
stbi_info(path.getAbsolutePath().c_str(), &w, &h, nullptr);
|
||||
// load image as float
|
||||
size = w * h * sizeof(float3);
|
||||
data = (float3*)stbi_loadf(path.getAbsolutePath().c_str(), &w, &h, &n, 3);
|
||||
destroyer = [](void* data, size_t, void*) {
|
||||
stbi_image_free(data);
|
||||
};
|
||||
}
|
||||
|
||||
if (data == nullptr || n != 3) {
|
||||
std::cerr << "Could not decode image " << std::endl;
|
||||
destroyer(data, size, user);
|
||||
int w, h;
|
||||
stbi_info(path.getAbsolutePath().c_str(), &w, &h, nullptr);
|
||||
if (w != h * 2) {
|
||||
std::cerr << "not an equirectangular image!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (w != h * 2) {
|
||||
std::cerr << "not an equirectangular image!" << std::endl;
|
||||
destroyer(data, size, user);
|
||||
// load image as float
|
||||
int n;
|
||||
const size_t size = w * h * sizeof(float3);
|
||||
float3* const data = (float3*)stbi_loadf(path.getAbsolutePath().c_str(), &w, &h, &n, 3);
|
||||
if (data == nullptr || n != 3) {
|
||||
std::cerr << "Could not decode image " << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// now load texture
|
||||
Texture::PixelBufferDescriptor buffer(
|
||||
data, size,Texture::Format::RGB, Texture::Type::FLOAT, destroyer, user);
|
||||
data, size,Texture::Format::RGB, Texture::Type::FLOAT,
|
||||
[](void* buffer, size_t size, void* user) { stbi_image_free(buffer); });
|
||||
|
||||
Texture* const equirect = Texture::Builder()
|
||||
.width((uint32_t)w)
|
||||
@@ -131,7 +102,7 @@ bool IBL::loadFromEquirect(Path const& path) {
|
||||
|
||||
mTexture = specularFilter(mSkyboxTexture);
|
||||
|
||||
mFogTexture = irradianceFilter({ .generateMipmap = false }, mSkyboxTexture);
|
||||
mFogTexture = irradianceFilter({ .generateMipmap=false }, mSkyboxTexture);
|
||||
mFogTexture->generateMipmaps(mEngine);
|
||||
|
||||
mIndirectLight = IndirectLight::Builder()
|
||||
|
||||
@@ -226,7 +226,7 @@ Texture* IBLPrefilterContext::EquirectangularToCubemap::operator()(
|
||||
Engine& engine = mContext.mEngine;
|
||||
View* const view = mContext.mView;
|
||||
Renderer* const renderer = mContext.mRenderer;
|
||||
MaterialInstance* const mi = mEquirectMaterial->createInstance();
|
||||
MaterialInstance* const mi = mEquirectMaterial->getDefaultInstance();
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(equirect != nullptr) << "equirect is null!";
|
||||
|
||||
@@ -289,8 +289,6 @@ Texture* IBLPrefilterContext::EquirectangularToCubemap::operator()(
|
||||
engine.destroy(rt);
|
||||
}
|
||||
|
||||
engine.destroy(mi);
|
||||
|
||||
return outCube;
|
||||
}
|
||||
|
||||
@@ -323,7 +321,7 @@ IBLPrefilterContext::IrradianceFilter::IrradianceFilter(IBLPrefilterContext& con
|
||||
.height(mSampleCount)
|
||||
.build(engine);
|
||||
|
||||
MaterialInstance* const mi = mKernelMaterial->createInstance();
|
||||
MaterialInstance* const mi = mKernelMaterial->getDefaultInstance();
|
||||
mi->setParameter("size", uint2{ 1, mSampleCount });
|
||||
mi->setParameter("sampleCount", float(mSampleCount));
|
||||
|
||||
@@ -341,7 +339,6 @@ IBLPrefilterContext::IrradianceFilter::IrradianceFilter(IBLPrefilterContext& con
|
||||
renderer->renderStandaloneView(view);
|
||||
|
||||
engine.destroy(rt);
|
||||
engine.destroy(mi);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
@@ -407,7 +404,7 @@ filament::Texture* IBLPrefilterContext::IrradianceFilter::operator()(
|
||||
Engine& engine = mContext.mEngine;
|
||||
View* const view = mContext.mView;
|
||||
Renderer* const renderer = mContext.mRenderer;
|
||||
MaterialInstance* const mi = mContext.mIrradianceIntegrationMaterial->createInstance();
|
||||
MaterialInstance* const mi = mContext.mIrradianceIntegrationMaterial->getDefaultInstance();
|
||||
|
||||
RenderableManager& rcm = engine.getRenderableManager();
|
||||
rcm.setMaterialInstanceAt(
|
||||
@@ -455,8 +452,6 @@ filament::Texture* IBLPrefilterContext::IrradianceFilter::operator()(
|
||||
engine.destroy(rt);
|
||||
}
|
||||
|
||||
engine.destroy(mi);
|
||||
|
||||
return outIrradianceTexture;
|
||||
}
|
||||
|
||||
@@ -527,7 +522,7 @@ IBLPrefilterContext::SpecularFilter::SpecularFilter(IBLPrefilterContext& context
|
||||
roughnessArray[i] = roughness;
|
||||
}
|
||||
|
||||
MaterialInstance* const mi = mKernelMaterial->createInstance();
|
||||
MaterialInstance* const mi = mKernelMaterial->getDefaultInstance();
|
||||
mi->setParameter("size", uint2{ mLevelCount, mSampleCount });
|
||||
mi->setParameter("sampleCount", float(mSampleCount));
|
||||
mi->setParameter("roughness", roughnessArray, 16);
|
||||
@@ -546,7 +541,6 @@ IBLPrefilterContext::SpecularFilter::SpecularFilter(IBLPrefilterContext& context
|
||||
renderer->renderStandaloneView(view);
|
||||
|
||||
engine.destroy(rt);
|
||||
engine.destroy(mi);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
@@ -640,7 +634,7 @@ Texture* IBLPrefilterContext::SpecularFilter::operator()(
|
||||
Engine& engine = mContext.mEngine;
|
||||
View* const view = mContext.mView;
|
||||
Renderer* const renderer = mContext.mRenderer;
|
||||
MaterialInstance* const mi = mContext.mIntegrationMaterial->createInstance();
|
||||
MaterialInstance* const mi = mContext.mIntegrationMaterial->getDefaultInstance();
|
||||
|
||||
RenderableManager& rcm = engine.getRenderableManager();
|
||||
rcm.setMaterialInstanceAt(
|
||||
@@ -707,7 +701,5 @@ Texture* IBLPrefilterContext::SpecularFilter::operator()(
|
||||
dim >>= 1;
|
||||
}
|
||||
|
||||
engine.destroy(mi);
|
||||
|
||||
return outReflectionsTexture;
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ public:
|
||||
using const_pointer = const TYPE*;
|
||||
using reference = TYPE&;
|
||||
using const_reference = const TYPE&;
|
||||
using size_type = ::size_t;
|
||||
using difference_type = ::ptrdiff_t;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using is_always_equal = std::true_type;
|
||||
|
||||
|
||||
+9
-14
@@ -515,9 +515,7 @@ static void onClick(App& app, View* view, ImVec2 pos) {
|
||||
|
||||
static utils::Path getPathForIBLAsset(std::string_view string) {
|
||||
auto isIBL = [] (utils::Path file) -> bool {
|
||||
return file.getExtension() == "ktx" || file.getExtension() == "hdr" ||
|
||||
file.getExtension() == "exr";
|
||||
|
||||
return file.getExtension() == "ktx" || file.getExtension() == "hdr";
|
||||
};
|
||||
|
||||
utils::Path filename{ string };
|
||||
@@ -673,15 +671,7 @@ int main(int argc, char** argv) {
|
||||
buffer.shrink_to_fit();
|
||||
};
|
||||
|
||||
auto setupIBL = [&app]() {
|
||||
auto ibl = FilamentApp::get().getIBL();
|
||||
if (ibl) {
|
||||
app.viewer->setIndirectLight(ibl->getIndirectLight(), ibl->getSphericalHarmonics());
|
||||
app.viewer->getSettings().view.fogSettings.fogColorTexture = ibl->getFogTexture();
|
||||
}
|
||||
};
|
||||
|
||||
auto loadResources = [&app, &setupIBL] (const utils::Path& filename) {
|
||||
auto loadResources = [&app] (const utils::Path& filename) {
|
||||
// Load external textures and buffers.
|
||||
std::string const gltfPath = filename.getAbsolutePath();
|
||||
ResourceConfiguration configuration = {};
|
||||
@@ -718,7 +708,12 @@ int main(int argc, char** argv) {
|
||||
instances[mi]->setStencilWrite(true);
|
||||
instances[mi]->setStencilOpDepthStencilPass(MaterialInstance::StencilOperation::INCR);
|
||||
}
|
||||
setupIBL();
|
||||
|
||||
auto ibl = FilamentApp::get().getIBL();
|
||||
if (ibl) {
|
||||
app.viewer->setIndirectLight(ibl->getIndirectLight(), ibl->getSphericalHarmonics());
|
||||
app.viewer->getSettings().view.fogSettings.fogColorTexture = ibl->getFogTexture();
|
||||
}
|
||||
};
|
||||
|
||||
auto setup = [&](Engine* engine, View* view, Scene* scene) {
|
||||
@@ -1195,7 +1190,7 @@ int main(int argc, char** argv) {
|
||||
filename = getPathForIBLAsset(path);
|
||||
if (!filename.isEmpty()) {
|
||||
FilamentApp::get().loadIBL(path);
|
||||
setupIBL();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -224,8 +224,6 @@ int main(int argc, char** argv) {
|
||||
app.stereoRenderTarget = RenderTarget::Builder()
|
||||
.texture(RenderTarget::AttachmentPoint::COLOR, app.stereoColorTexture)
|
||||
.texture(RenderTarget::AttachmentPoint::DEPTH, app.stereoDepthTexture)
|
||||
.multiview(RenderTarget::AttachmentPoint::COLOR, eyeCount, 0)
|
||||
.multiview(RenderTarget::AttachmentPoint::DEPTH, eyeCount, 0)
|
||||
.build(*engine);
|
||||
app.stereoView->setRenderTarget(app.stereoRenderTarget);
|
||||
app.stereoView->setViewport({0, 0, vp.width, vp.height});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.55.0",
|
||||
"version": "1.54.2",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user