Compare commits

..

4 Commits

Author SHA1 Message Date
Syed Idris Shah
5d59459f90 Dawn change to enable writeBuffer for size != multiple of 4 2025-05-06 14:07:05 -04:00
bridgewaterrobbie
4249ff6cfb WebGPU: HelloTraingle hacks
Co-authored-by: Andy Hovingh <6198728+AndyHovingh@users.noreply.github.com>
2025-05-06 14:07:05 -04:00
bridgewaterrobbie
1076433fc0 Use variant layout label if available 2025-05-06 14:06:53 -04:00
bridgewaterrobbie
3bd0039ee9 Minimal labels implementation for descriptorset layout 2025-05-06 13:22:33 -04:00
146 changed files with 1407 additions and 2906 deletions

View File

@@ -3,5 +3,5 @@ runs:
using: "composite"
steps:
- name: Set up dependency versions
shell: bash
shell: bash
run: cat ./build/common/versions >> $GITHUB_ENV

View File

@@ -1,16 +0,0 @@
name: 'Web Preqrequisites'
runs:
using: "composite"
steps:
- uses: ./.github/actions/dep-versions
- name: Cache EMSDK
id: emsdk-cache
uses: actions/cache@v4 # Use a specific version
with:
path: emsdk
key: ${{ runner.os }}-emsdk-${{ env.GITHUB_EMSDK_VERSION }}
- name: Install Web Prerequisites
shell: bash
run: |
bash ./build/common/get-emscripten.sh
echo "EMSDK=$PWD/emsdk" >> $GITHUB_ENV

View File

@@ -26,4 +26,4 @@ jobs:
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
test/check-headers/test.sh out/release/filament/include
build/common/check-headers.sh out/release/filament/include

View File

@@ -96,7 +96,6 @@ jobs:
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh presubmit
@@ -124,15 +123,13 @@ jobs:
- uses: ./.github/actions/mac-prereq
- name: Cache Mesa and deps
id: mesa-cache
uses: actions/cache@v4
uses: actions/cache@v4 # Use a specific version
with:
path: mesa
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
- name: Prerequisites
id: prereqs
run: |
bash build/common/get-mesa.sh
pip install tifffile numpy
- name: Get Mesa
id: mesa-prereq
run: bash test/utils/get_mesa.sh
- name: Run Test
run: bash test/renderdiff/test.sh
- uses: actions/upload-artifact@v4
@@ -153,8 +150,8 @@ jobs:
- name: Run test
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
test-code-correctness:
name: test-code-correctness
code-correcteness:
name: code-correctness
runs-on: 'macos-14-xlarge'
steps:
- uses: actions/checkout@v4.1.6

View File

@@ -65,9 +65,13 @@ jobs:
build-mac:
name: build-mac
runs-on: macos-14-xlarge
runs-on: ${{ matrix.os }}
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
strategy:
matrix:
os: [macos-14-xlarge, ubuntu-22.04-32core]
steps:
- name: Decide Git ref
id: git_ref
@@ -114,7 +118,6 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
@@ -163,9 +166,6 @@ jobs:
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
cd out/android-release/filament
tar -czf ../../filament-${TAG}-android-native.tgz .
cd ../../..
- name: Sign sample-gltf-viewer
run: |
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
@@ -187,7 +187,7 @@ jobs:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create(['out/*.aar', 'out/*.apk', 'out/*.tgz'].join('\n'));
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
await upload({ github, context }, await globber.glob(), TAG);
build-ios:

View File

@@ -17,7 +17,6 @@ jobs:
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- uses: ./.github/actions/web-prereq
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh continuous

View File

@@ -363,8 +363,6 @@ python ./emsdk.py activate latest
source ./emsdk_env.sh
```
Alternatively, you can try running the script `build/common/get-emscripten.sh`.
After this you can invoke the [easy build](#easy-build) script as follows:
```shell

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.60.0'
implementation 'com.google.android.filament:filament-android:1.59.4'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.60.0'
pod 'Filament', '~> 1.59.4'
```
## Documentation

View File

@@ -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.60.1
## v1.60.0
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
- matc non-functional change: Update GLSL postprocessor to
isolate calls to SPVRemap from calls to SPIRV-Cross.
## v1.59.5

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.60.0
VERSION_NAME=1.59.4
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -151,7 +151,7 @@ function print_fgviewer_help {
}
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | sed s/GITHUB_NDK_VERSION=//g | cut -f 1 -d ".")}
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")}
# Requirements
CMAKE_MAJOR=3
@@ -463,6 +463,16 @@ function ensure_android_build {
echo "Error: Android NDK side-by-side version ${FILAMENT_NDK_VERSION} or compatible must be installed, exiting"
exit 1
fi
local cmake_version=$(cmake --version)
if [[ "${cmake_version}" =~ ([0-9]+)\.([0-9]+)\.[0-9]+ ]]; then
if [[ "${BASH_REMATCH[1]}" -lt "${CMAKE_MAJOR}" ]] || \
[[ "${BASH_REMATCH[2]}" -lt "${CMAKE_MINOR}" ]]; then
echo "Error: cmake version ${CMAKE_MAJOR}.${CMAKE_MINOR}+ is required," \
"${BASH_REMATCH[1]}.${BASH_REMATCH[2]} installed, exiting"
exit 1
fi
fi
}
function build_android {

View File

@@ -1,6 +1,28 @@
#!/bin/bash
source `dirname $0`/../common/ci-check.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
set -e
set -x
@@ -8,6 +30,11 @@ set -x
UNAME=`echo $(uname)`
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
# build-common.sh will generate the following variables:
# $GENERATE_ARCHIVES
# $BUILD_DEBUG
# $BUILD_RELEASE
source `dirname $0`/../common/ci-common.sh
source `dirname $0`/../common/build-common.sh
if [[ "$GITHUB_WORKFLOW" ]]; then

View File

@@ -1,20 +1,5 @@
#!/bin/bash
# build-common.sh will generate the following variables:
# $GENERATE_ARCHIVES
# $BUILD_DEBUG
# $BUILD_RELEASE
# Typically a build script (build.sh) would source this script. For example,
# source `dirname $0`/../common/build-common.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
if [[ ! "$TARGET" ]]; then
if [[ "$1" ]]; then
TARGET=$1

View File

@@ -1,19 +0,0 @@
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
if [[ "$GITHUB_WORKFLOW" ]]; then
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
fi

5
build/common/ci-common.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
if [[ "$GITHUB_WORKFLOW" ]]; then
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
fi

View File

@@ -1,22 +0,0 @@
#!/bin/bash
if [ -d "./emsdk" ]; then
echo "emsdk folder found. Assume emsdk has been installed."
cd emsdk
./emsdk activate latest
source ./emsdk_env.sh
export EMSDK="$PWD"
cd ..
exit 0
fi
# Install emscripten.
EMSDK_VERSION=${GITHUB_EMSDK_VERSION-3.1.60}
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/${EMSDK_VERSION}.zip > emsdk.zip
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
export EMSDK="$PWD"
cd ..

View File

@@ -3,5 +3,4 @@ GITHUB_CMAKE_VERSION=3.19.5
GITHUB_NINJA_VERSION=1.10.2
GITHUB_MESA_VERSION=24.2.1
GITHUB_LLVM_VERSION=16
GITHUB_NDK_VERSION=27.0.11718014
GITHUB_EMSDK_VERSION=3.1.60
GITHUB_NDK_VERSION=27.0.11718014

View File

@@ -1,11 +1,35 @@
#!/bin/bash
source `dirname $0`/../common/ci-check.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
set -e
set -x
source `dirname $0`/../common/ci-common.sh
source `dirname $0`/../common/build-common.sh
pushd `dirname $0`/../.. > /dev/null
# If we're generating an archive for release or continuous builds, then we'll also build for the

View File

@@ -1,11 +1,38 @@
#!/bin/bash
source `dirname $0`/../common/ci-check.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
set -e
set -x
# build-common.sh will generate the following variables:
# $GENERATE_ARCHIVES
# $BUILD_DEBUG
# $BUILD_RELEASE
source `dirname $0`/../common/ci-common.sh
source `dirname $0`/../common/build-common.sh
pushd `dirname $0`/../.. > /dev/null
pushd `dirname $0`/../.. > /dev/null
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE

View File

@@ -1,11 +1,34 @@
#!/bin/bash
source `dirname $0`/../common/ci-check.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
set -e
set -x
source `dirname $0`/../common/ci-common.sh
source `dirname $0`/../common/build-common.sh
pushd `dirname $0`/../.. > /dev/null
pushd `dirname $0`/../.. > /dev/null
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE

View File

@@ -1,10 +1,34 @@
#!/bin/bash
source `dirname $0`/../common/ci-check.sh
# Usage: the first argument selects the build type:
# - release, to build release only
# - debug, to build debug only
# - continuous, to build release and debug
# - presubmit, for presubmit builds
#
# The default is release
echo "This script is intended to run in a CI environment and may modify your current environment."
echo "Please refer to BUILDING.md for more information."
read -r -p "Do you wish to proceed (y/n)? " choice
case "${choice}" in
y|Y)
echo "Build will proceed..."
;;
n|N)
exit 0
;;
*)
exit 0
;;
esac
set -e
set -x
source `dirname $0`/../common/ci-common.sh
source `dirname $0`/ci-common.sh
source `dirname $0`/../common/build-common.sh
pushd `dirname $0`/../.. > /dev/null

11
build/web/ci-common.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
# Install emscripten.
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.60.zip > emsdk.zip
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
export EMSDK="$PWD"
cd ..

View File

@@ -1023,12 +1023,8 @@ samplerCubemap | Cubemap texture
[Table [materialParamsTypes]: Material parameter types]
Samplers
: Sampler types can specify additional options:
- `format`: either `int` or `float` (defaults to `float`).
- `stages`: array of strings containing the list of shader stages this
sampler can be accessed from. Each entry must be either `vertex` or
`fragment` (defaults to both).
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
`float`).
Arrays
: A parameter can define an array of values by appending `[size]` after the type name, where

View File

@@ -18,8 +18,6 @@
- [Metal](./notes/metal_debugging.md)
- [Vulkan](./notes/vulkan_debugging.md)
- [SPIR-V](./notes/spirv_debugging.md)
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
- [Using Instruments on macOS](./notes/instruments.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
- [bluevk](./dup/bluevk.md)

View File

@@ -1,41 +0,0 @@
# Running with ASAN/UBSAN
## Enabling
When building though build.sh, pass the `-b` flag. This sets the cmake variable
`FILAMENT_ENABLE_ASAN_UBSAN=ON` which eventually passes `"-fsanitize=address -fsanitize=undefined"`
to all compile and link operations.
If building through CMake directly, or an IDE like CLion that doesn't use build.sh, instead pass
`-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to cmake in order to get the same result.
## Getting memory leak detection on Mac
Memory leak detection isn't enabled by default on MacOS. There are two issues to address, first is
using a version of clang that supports memory leak detection and second is enabling it at runtime.
The version of clang distributed by Apple (with a version like "Apple clang version 16.0.0") doesn't
currently support leak detection at all. Instead you will need to get or build a different LLVM,
such as the one distributed through homebrew and get CMake to use that instead.
Then during runtime you'll need to have the environment variable `ASAN_OPTIONS` include the option
`detect_leaks=1`. Multiple `ASAN_OPTIONS` values are concatenated with `:`.
## Getting memory leak output in CLion
### Setting variables
Under `Settings | Build, Execution, Deployment | Dynamic Analysis Tools | Sanitizers` there is an
ASAN Settings field that overrides whatever other `ASAN_OPTIONS` you might set elsewhere, so you
must use that instead of setting it through your Run/Debug Configuration.
To pass `-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to CMake you'll want to create a new CMake Profile and
pass it as a CMake argument.
### Avoiding losing output
CMake will consume ASAN output and display it through a separate "Sanitizers" tab. Unfortunately
certain leak detection errors that interrupt the executable seem to not show up in this tab, but are
still removed from the user-visible console output. If this is happening and you need to see the
unfiltered console output you'll need to go to `Settings | Build, Execution, Deployment | Dynamic
Analysis Tools | Sanitizers` and uncheck "Use visual representation for Sanitizer's output".

View File

@@ -1,36 +0,0 @@
# Using Instruments on macOS
When running a binary under Instruments on macOS, you may run into the following issue when
launching or attaching to an executable:
```
Failed to gain authorization
Recovery Suggestion: Target binary needs to be debuggable and signed with 'get-task-allow'
```
This is a security precaution; the solution is to code sign the binary with the
`com.apple.security.get-task-allow` entitlement.
1. Create an `entitlements.plist` file with the following contents:
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
```
2. Run the following command:
```
codesign -s - --entitlements entitlements.plist <binary>
```
Replace `<binary>` with the name of the binary, for example: `out/cmake-debug/samples/gltf_viewer`.
Afterwards, you should be able to successfully launch and attach to the executable using
Instruments.

View File

@@ -5,6 +5,18 @@ set(TARGET backend)
set(PUBLIC_HDR_DIR include)
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
# ==================================================================================================
# Compilation options
# ==================================================================================================
#
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
set(BACKEND_SANITIZERS)
if (BACKEND_SANITIZATION STREQUAL "ASAN")
set(BACKEND_SANITIZERS -fsanitize=address)
endif()
# ==================================================================================================
# Sources and headers
# ==================================================================================================
@@ -472,6 +484,7 @@ target_compile_options(${TARGET} PRIVATE
${OSMESA_COMPILE_FLAGS}
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
${BACKEND_SANITIZERS}
)
if (FILAMENT_SUPPORTS_METAL)
@@ -482,6 +495,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
endif()
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(${TARGET} PRIVATE
${OSMESA_LINKER_FLAGS}
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
@@ -551,6 +566,8 @@ if (APPLE AND NOT IOS)
test/test_RenderExternalImage.cpp)
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
set(BACKEND_TEST_DEPS
OSDependent
@@ -589,6 +606,7 @@ if (APPLE AND NOT IOS)
# linker from removing "unused" symbols.
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
# This is needed after XCode 15.3
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
@@ -598,6 +616,8 @@ endif()
if (LINUX)
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
endif()

View File

@@ -20,15 +20,10 @@
#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H
#include <utils/compiler.h>
#include <utility>
#include <utils/ostream.h>
#include <stddef.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
class CallbackHandler;
@@ -94,8 +89,8 @@ public:
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
* @param user An opaque user pointer passed to the callback function when it's called
*/
BufferDescriptor(void const* buffer, size_t const size,
Callback const callback = nullptr, void* user = nullptr) noexcept
BufferDescriptor(void const* buffer, size_t size,
Callback callback = nullptr, void* user = nullptr) noexcept
: buffer(const_cast<void*>(buffer)), size(size), mCallback(callback), mUser(user) {
}
@@ -103,12 +98,11 @@ public:
* Creates a BufferDescriptor that references a CPU memory-buffer
* @param buffer Memory address of the CPU buffer to reference
* @param size Size of the CPU buffer in bytes
* @param handler A custom handler for the callback
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
* @param user An opaque user pointer passed to the callback function when it's called
*/
BufferDescriptor(void const* buffer, size_t const size,
CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept
BufferDescriptor(void const* buffer, size_t size,
CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept
: buffer(const_cast<void*>(buffer)), size(size),
mCallback(callback), mUser(user), mHandler(handler) {
}
@@ -122,9 +116,8 @@ public:
*
* @param buffer Memory address of the CPU buffer to reference
* @param size Size of the CPU buffer in bytes
* @param data A pointer to the data
* @param handler Handler to use to dispatch the callback, or nullptr for the default handler
* @return A new BufferDescriptor
* @return a new BufferDescriptor
*/
template<typename T, void(T::*method)(void const*, size_t)>
static BufferDescriptor make(void const* buffer, size_t size, T* data,
@@ -171,7 +164,7 @@ public:
* @param callback The new callback function
* @param user An opaque user pointer passed to the callbeck function when it's called
*/
void setCallback(Callback const callback, void* user = nullptr) noexcept {
void setCallback(Callback callback, void* user = nullptr) noexcept {
this->mCallback = callback;
this->mUser = user;
this->mHandler = nullptr;
@@ -183,7 +176,7 @@ public:
* @param callback The new callback function
* @param user An opaque user pointer passed to the callbeck function when it's called
*/
void setCallback(CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept {
void setCallback(CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept {
mCallback = callback;
mUser = user;
mHandler = handler;

View File

@@ -19,6 +19,8 @@
#include <backend/DriverApiForward.h>
#include <utils/ostream.h>
#include <initializer_list>
#include <memory>
@@ -26,10 +28,6 @@
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept;

View File

@@ -25,11 +25,11 @@
#include <backend/PresentCallable.h>
#include <utils/BitmaskEnum.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/StaticString.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <math/vec4.h>
@@ -39,10 +39,7 @@
#include <stddef.h>
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
#include <utils/StaticString.h>
/**
* Types and enums used by filament's driver.

View File

@@ -17,6 +17,9 @@
#ifndef TNT_FILAMENT_BACKEND_HANDLE_H
#define TNT_FILAMENT_BACKEND_HANDLE_H
#if !defined(NDEBUG)
#include <utils/ostream.h>
#endif
#include <utils/debug.h>
#include <type_traits> // FIXME: STL headers are not allowed in public headers
@@ -24,10 +27,6 @@
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
struct HwBufferObject;

View File

@@ -20,14 +20,12 @@
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <utils/ostream.h>
#include <array>
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
//! \privatesection

View File

@@ -24,14 +24,11 @@
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <stddef.h>
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
/**

View File

@@ -20,10 +20,12 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/ostream.h>
#include <backend/DriverEnums.h>
#include <array>
#include <unordered_map>
#include <tuple>
#include <utility>
#include <variant>
@@ -31,10 +33,6 @@
#include <stddef.h>
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
class Program {
@@ -46,8 +44,8 @@ public:
struct Descriptor {
utils::CString name;
DescriptorType type;
descriptor_binding_t binding;
backend::DescriptorType type;
backend::descriptor_binding_t binding;
};
struct SpecializationConstant {

View File

@@ -19,26 +19,22 @@
#include <backend/Handle.h>
#include <utility>
#include <utils/ostream.h>
#include <stddef.h>
#include <stdint.h>
namespace utils::io {
class ostream;
} // namespace utils::io
namespace filament::backend {
//! \privatesection
struct TargetBufferInfo {
// note: the parameters of this constructor are not in the order of this structure's fields
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level, uint16_t const layer) noexcept
: handle(std::move(handle)), level(level), layer(layer) {
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: handle(handle), level(level), layer(layer) {
}
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level) noexcept
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level) noexcept
: handle(handle), level(level) {
}
@@ -74,11 +70,11 @@ private:
TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT];
public:
TargetBufferInfo const& operator[](size_t const i) const noexcept {
TargetBufferInfo const& operator[](size_t i) const noexcept {
return mInfos[i];
}
TargetBufferInfo& operator[](size_t const i) noexcept {
TargetBufferInfo& operator[](size_t i) noexcept {
return mInfos[i];
}

View File

@@ -39,40 +39,18 @@ public:
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
int getOSVersion() const noexcept override { return 0; }
/**
* Optionally initializes the Metal platform by acquiring resources necessary for rendering.
*
* This method attempts to acquire a Metal device and command queue, returning true if both are
* successfully obtained, or false otherwise. Typically, these objects are acquired when
* the Metal backend is initialized. This method allows clients to check for their availability
* earlier.
*
* Calling initialize() is optional and safe to do so multiple times. After initialize() returns
* true, subsequent calls will continue to return true but have no effect.
*
* initialize() must be called from the main thread.
*
* @returns true if the device and command queue have been successfully obtained; false
* otherwise.
*/
bool initialize() noexcept;
/**
* Obtain the preferred Metal device object for the backend to use.
*
* On desktop platforms, there may be multiple GPUs suitable for rendering, and this method is
* free to decide which one to use. On mobile systems with a single GPU, implementations should
* simply return the result of MTLCreateSystemDefaultDevice();
*
* createDevice is called by the Metal backend from the backend thread.
*/
virtual void createDevice(MetalDevice& outDevice) noexcept;
/**
* Create a command submission queue on the Metal device object.
*
* createCommandQueue is called by the Metal backend from the backend thread.
*
* @param device The device which was returned from createDevice()
*/
virtual void createCommandQueue(
@@ -82,8 +60,6 @@ public:
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
* guaranteed to execute before all subsequent command buffers created either by Filament, or
* further calls to this method.
*
* createAndEnqueueCommandBuffer must be called from the main thread.
*/
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
@@ -92,8 +68,6 @@ public:
*
* Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the
* completion of each frame. These are limited and provided round-robin style by the system.
*
* setDrawableFailureBehavior must be called from the main thread.
*/
enum class DrawableFailureBehavior : uint8_t {
/**

View File

@@ -27,11 +27,8 @@
#include <utils/Hash.h>
#include <utils/PrivateImplementation.h>
#include <cstddef>
#include <functional>
#include <tuple>
#include <unordered_set>
#include <string>
#include <stddef.h>
#include <stdint.h>

View File

@@ -84,7 +84,7 @@ void CommandStream::execute(void* buffer) {
Profiler profiler;
if (SYSTRACE_TAG) {
if constexpr (SYSTRACE_TAG) {
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
// we want to remove all this when tracing is completely disabled
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
@@ -100,7 +100,7 @@ void CommandStream::execute(void* buffer) {
}
});
if (SYSTRACE_TAG) {
if constexpr (SYSTRACE_TAG) {
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
// we want to remove all this when tracing is completely disabled
profiler.stop();

View File

@@ -17,7 +17,6 @@
#include <backend/Platform.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <atomic>
#include <utility>

View File

@@ -19,8 +19,6 @@
#include "MetalContext.h"
#include <utils/Panic.h>
namespace filament {
namespace backend {

View File

@@ -721,25 +721,15 @@ const char* toString(DescriptorFlags flags) {
void MetalDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info) {
#if FILAMENT_METAL_DEBUG_LOG == 1
const char* labelStr = "";
std::visit([&labelStr](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, utils::CString> || std::is_same_v<T, utils::StaticString>) {
labelStr = arg.c_str();
}
}, info.label);
std::sort(info.bindings.begin(), info.bindings.end(),
[](const auto& a, const auto& b) { return a.binding < b.binding; });
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = { label = %s,\n", dslh.getId(),
labelStr);
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",
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");
#endif
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
}

View File

@@ -185,7 +185,6 @@ inline MTLPixelFormat getMetalFormat(PixelDataFormat format, PixelDataType type)
CONVERT(RGBA_INTEGER, UINT, RGBA32Uint);
CONVERT(RGBA_INTEGER, INT, RGBA32Sint);
CONVERT(RGBA, FLOAT, RGBA32Float);
CONVERT(DEPTH_COMPONENT, FLOAT, Depth32Float);
#undef CONVERT
return MTLPixelFormatInvalid;

View File

@@ -1382,9 +1382,6 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
break;
}
}
if (arguments.count == 0) {
return nil;
}
return [device newArgumentEncoderWithArguments:arguments];
}
@@ -1445,9 +1442,6 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
id<MTLArgumentEncoder> encoder =
layout->getArgumentEncoder(context.device, stage, textureTypes);
if (!encoder) {
return nil;
}
{
ScopedAllocationTimer timer("descriptor_set");

View File

@@ -20,18 +20,17 @@
#include <Metal/Metal.h>
#include "private/backend/Driver.h"
#include "backend/Program.h"
#include <backend/DriverEnums.h>
#include <backend/Program.h>
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Hash.h>
#include <utils/Invocable.h>
#include <tsl/robin_map.h>
#include <memory>
#include <tsl/robin_map.h>
#include <utils/Hash.h>
#include <utils/Invocable.h>
namespace filament {
namespace backend {

View File

@@ -24,22 +24,14 @@
#import <Foundation/Foundation.h>
#include <atomic>
#include <mutex>
namespace filament::backend {
struct PlatformMetalImpl {
std::mutex mLock; // locks mDevice and mCommandQueue
id<MTLDevice> mDevice = nil;
id<MTLCommandQueue> mCommandQueue = nil;
// read form driver thread, read/written to from client thread
std::atomic<PlatformMetal::DrawableFailureBehavior> mDrawableFailureBehavior =
PlatformMetal::DrawableFailureBehavior::PANIC;
// These methods must be called with mLock held
void createDeviceImpl(MetalDevice& outDevice);
void createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue);
};
Platform* createDefaultMetalPlatform() {
@@ -56,59 +48,7 @@ Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::Dri
return MetalDriverFactory::create(this, driverConfig);
}
bool PlatformMetal::initialize() noexcept {
std::lock_guard<std::mutex> lock(pImpl->mLock);
MetalDevice device{};
pImpl->createDeviceImpl(device);
if (device.device == nil) {
return false;
}
MetalCommandQueue commandQueue{};
pImpl->createCommandQueueImpl(device, commandQueue);
if (commandQueue.commandQueue == nil) {
return false;
}
return true;
}
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
std::lock_guard<std::mutex> lock(pImpl->mLock);
pImpl->createDeviceImpl(outDevice);
}
void PlatformMetal::createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
std::lock_guard<std::mutex> lock(pImpl->mLock);
pImpl->createCommandQueueImpl(device, outCommandQueue);
}
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
std::lock_guard<std::mutex> lock(pImpl->mLock);
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
[commandBuffer enqueue];
outCommandBuffer.commandBuffer = commandBuffer;
}
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
pImpl->mDrawableFailureBehavior = behavior;
}
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
return pImpl->mDrawableFailureBehavior;
}
// -------------------------------------------------------------------------------------------------
void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
if (mDevice) {
outDevice.device = mDevice;
return;
}
id<MTLDevice> result;
#if !defined(FILAMENT_IOS)
@@ -134,17 +74,27 @@ void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
<< utils::io::endl;
outDevice.device = result;
mDevice = result;
}
void PlatformMetalImpl::createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue) {
if (mCommandQueue) {
outCommandQueue.commandQueue = mCommandQueue;
return;
}
mCommandQueue = [device.device newCommandQueue];
mCommandQueue.label = @"Filament";
outCommandQueue.commandQueue = mCommandQueue;
void PlatformMetal::createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
pImpl->mCommandQueue = [device.device newCommandQueue];
pImpl->mCommandQueue.label = @"Filament";
outCommandQueue.commandQueue = pImpl->mCommandQueue;
}
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
[commandBuffer enqueue];
outCommandBuffer.commandBuffer = commandBuffer;
}
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
pImpl->mDrawableFailureBehavior = behavior;
}
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
return pImpl->mDrawableFailureBehavior;
}
} // namespace filament

View File

@@ -542,13 +542,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
} else if (strstr(renderer, "Intel")) {
// Intel GPU
bugs->vao_doesnt_store_element_array_buffer_binding = true;
if (strstr(renderer, "Mesa")) {
// Mesa Intel driver on Linux/Android
// Renderer of the form [Mesa Intel(R) HD Graphics 505 (APL 3)]
// b/405252622
bugs->disable_invalidate_framebuffer = true;
}
} else if (strstr(renderer, "PowerVR")) {
// PowerVR GPU
// On PowerVR (Rogue GE8320) glFlush doesn't seem to do anything, in particular,

View File

@@ -54,7 +54,7 @@ struct PlatformCocoaGLImpl {
CVOpenGLTextureCacheRef mTextureCache = nullptr;
std::unique_ptr<CocoaExternalImage::SharedGl> mExternalImageSharedGl;
void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView);
struct ExternalImageCocoaGL final : public Platform::ExternalImage {
struct ExternalImageCocoaGL : public Platform::ExternalImage {
CVPixelBufferRef cvBuffer;
protected:
~ExternalImageCocoaGL() noexcept final;

View File

@@ -152,12 +152,12 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
#elif FVK_ENABLED(FVK_DEBUG_SYSTRACE)
#include <utils/Systrace.h>
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
#define FVK_SYSTRACE_SCOPE() SYSTRACE_NAME(__func__)
#define FVK_PROFILE_MARKER(marker) FVK_SYSTRACE_SCOPE()
#define FVK_SYSTRACE_SCOPE() SYSTRACE_CALL()
#define FVK_PROFILE_MARKER(marker) SYSTRACE_CALL()
#else
#define FVK_SYSTRACE_CONTEXT()

View File

@@ -142,10 +142,6 @@ public:
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
}
inline bool isUnifiedMemoryArchitecture() const noexcept {
return mIsUnifiedMemoryArchitecture;
}
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
@@ -168,7 +164,6 @@ private:
bool mDebugUtilsSupported = false;
bool mLazilyAllocatedMemorySupported = false;
bool mProtectedMemorySupported = false;
bool mIsUnifiedMemoryArchitecture = false;
fvkutils::VkFormatList mDepthStencilFormats;
fvkutils::VkFormatList mBlittableDepthStencilFormats;

View File

@@ -631,21 +631,6 @@ fvkutils::VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device)
return ret;
}
/**
* Check if the GPU has a unified memory architecture.
*/
bool hasUnifiedMemoryArchitecture(VkPhysicalDeviceMemoryProperties memoryProperties) noexcept {
// Try to identify if the platform is running on a Unified Memory Architecture by inspecting the
// memory heap flags, if they are all VK_MEMORY_HEAP_DEVICE_LOCAL_BIT it's UMA, otherwise not
// enough information to make a decision, so default to false.
for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; ++i) {
if ((memoryProperties.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0) {
return false;
}
}
return true;
}
}// anonymous namespace
using SwapChainPtr = VulkanPlatform::SwapChainPtr;
@@ -879,8 +864,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
}
}
context.mIsUnifiedMemoryArchitecture = hasUnifiedMemoryArchitecture(context.mMemoryProperties);
#ifdef NDEBUG
// If we are in release build, we should not have turned on debug extensions
FILAMENT_CHECK_POSTCONDITION(!context.mDebugUtilsSupported && !context.mDebugMarkersSupported)

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <utils/Hash.h>
#include "webgpu/WebGPUDriver.h"
#include "WebGPUPipelineCreation.h"
@@ -916,14 +916,6 @@ void WebGPUDriver::blit(
}
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
// TODO Investigate implications of this hash more closely. Vulkan has a whole class
// VulkanPipelineCache to handle this, may be missing nuance
static auto pipleineStateHasher = utils::hash::MurmurHashFn<filament::backend::PipelineState>();
auto hash = pipleineStateHasher(pipelineState);
if(mPipelineMap.find(hash) != mPipelineMap.end()){
mRenderPassEncoder.SetPipeline(mPipelineMap[hash]);
return;
}
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
assert_invariant(program);
assert_invariant(program->computeShaderModule == nullptr &&
@@ -960,7 +952,7 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
*vertexBufferInfo, layout, pipelineState.rasterState, pipelineState.stencilState,
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
mSwapChain->getDepthFormat());
mPipelineMap[hash] = pipeline;
// TODO: uncomment once we have a valid pipeline to set
mRenderPassEncoder.SetPipeline(pipeline);
}

View File

@@ -93,8 +93,6 @@ private:
wgpu::RenderPassEncoder mRenderPassEncoder = nullptr;
wgpu::CommandBuffer mCommandBuffer = nullptr;
WGPURenderTarget* mDefaultRenderTarget = nullptr;
tsl::robin_map<uint32_t, wgpu::RenderPipeline> mPipelineMap;
/*
* Driver interface
*/

View File

@@ -19,7 +19,6 @@
#include <backend/DriverEnums.h>
#include <utils/BitmaskEnum.h>
#include <utils/Panic.h>
#include <webgpu/webgpu_cpp.h>
@@ -503,6 +502,7 @@ size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
return mEntriesByBindingWithDynamicOffsets.count();
}
// From createTextureR
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
wgpu::Device const& device) noexcept {
@@ -516,7 +516,6 @@ WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat forma
// First, the texture aspect, starting with the defaults/basic configuration
mUsage = fToWGPUTextureUsage(usage);
mFormat = fToWGPUTextureFormat(format);
mAspect = fToWGPUTextureViewAspect(usage, format);
wgpu::TextureDescriptor textureDescriptor{
.label = getUserTextureLabel(target),
.usage = mUsage,
@@ -561,12 +560,13 @@ WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat forma
mTexView = makeTextureView(0, levels, target);
}
// From createTextureViewR
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
mTexture = src->mTexture;
mTexView = makeTextureView(baseLevel, levelCount, target);
}
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(TextureUsage const& fUsage) {
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
@@ -614,9 +614,8 @@ wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(TextureUsage const& fUsage)
// PROTECTED
return retUsage;
}
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFormat) {
switch (fFormat) {
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
switch (fUsage) {
case filament::backend::TextureFormat::R8:
return wgpu::TextureFormat::R8Unorm;
case filament::backend::TextureFormat::R8_SNORM:
@@ -855,57 +854,24 @@ wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(TextureFormat const& fForm
}
}
wgpu::TextureAspect WGPUTexture::fToWGPUTextureViewAspect(TextureUsage const& fUsage,
TextureFormat const& fFormat) {
const bool isDepth = any(fUsage & TextureUsage::DEPTH_ATTACHMENT);
const bool isStencil = any(fUsage & TextureUsage::STENCIL_ATTACHMENT);
const bool isColor = any(fUsage & TextureUsage::COLOR_ATTACHMENT);
const bool isSample = (fUsage == TextureUsage::SAMPLEABLE);
if (isDepth && !isColor && !isStencil) {
return wgpu::TextureAspect::DepthOnly;
}
if (isStencil && !isColor && !isDepth) {
return wgpu::TextureAspect::StencilOnly;
}
if (fFormat == filament::backend::TextureFormat::DEPTH32F ||
fFormat == filament::backend::TextureFormat::DEPTH24 ||
fFormat == filament::backend::TextureFormat::DEPTH16) {
return wgpu::TextureAspect::DepthOnly;
}
if (fFormat == filament::backend::TextureFormat::STENCIL8) {
return wgpu::TextureAspect::StencilOnly;
}
if (fFormat == filament::backend::TextureFormat::DEPTH24_STENCIL8 ||
fFormat == filament::backend::TextureFormat::DEPTH32F_STENCIL8) {
if (isSample) {
return wgpu::TextureAspect::DepthOnly;
}
}
return wgpu::TextureAspect::All;
}
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
SamplerType target) {
// starting with the defaults/basic configuration
wgpu::TextureViewDescriptor textureViewDescriptor{
.label = getUserTextureViewLabel(target),
.format = mFormat,
// dimension depends on target and is set below
.baseMipLevel = baseLevel,
.mipLevelCount = levelCount,
// TODO: check if this baseArrayLayer assumption is correct
// baseArrayLayer is required, making a guess
.baseArrayLayer = 0,
.arrayLayerCount = mArrayLayerCount,
.aspect = mAspect,
// Have not found an analog to aspect in other drivers, but ALL should be unrestrictive.
// TODO Can we make this better?
.aspect = wgpu::TextureAspect::All,
.usage = mUsage
};
// adjust for specific cases
switch (target) {
case SamplerType::SAMPLER_2D:
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;

View File

@@ -74,8 +74,8 @@ public:
private:
// TODO: can we do better in terms on heap management.
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout{};
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes{};
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout {};
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes {};
};
struct WGPUVertexBuffer : public HwVertexBuffer {
@@ -145,8 +145,8 @@ public:
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
private:
static wgpu::Buffer sDummyUniformBuffer;
static wgpu::Texture sDummyTexture;
static wgpu::TextureView sDummyTextureView;
@@ -161,10 +161,10 @@ private:
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
wgpu::BindGroupLayout mLayout = nullptr;
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding {};
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets{};
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded{};
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets {};
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded {};
std::vector<uint32_t> mDynamicOffsets;
wgpu::BindGroup mBindGroup = nullptr;
};
@@ -177,14 +177,11 @@ public:
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
[[nodiscard]] const wgpu::Texture& getTexture() const { return mTexture; }
[[nodiscard]] const wgpu::TextureView& getTexView() const { return mTexView; }
const wgpu::Texture& getTexture() const { return mTexture; }
const wgpu::TextureView& getTexView() const { return mTexView; }
static wgpu::TextureFormat fToWGPUTextureFormat(
filament::backend::TextureFormat const& fFormat);
static wgpu::TextureAspect fToWGPUTextureViewAspect(
filament::backend::TextureUsage const& fUsage,
filament::backend::TextureFormat const& fFormat);
// Public to allow checking for support of a texture format
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
private:
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
@@ -195,10 +192,9 @@ private:
wgpu::Texture mTexture = nullptr;
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
wgpu::TextureFormat mFormat = wgpu::TextureFormat::Undefined;
wgpu::TextureAspect mAspect = wgpu::TextureAspect::Undefined;
uint32_t mArrayLayerCount = 1;
wgpu::TextureView mTexView = nullptr;
wgpu::TextureUsage fToWGPUTextureUsage(filament::backend::TextureUsage const& fUsage);
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
};
struct WGPURenderPrimitive : public HwRenderPrimitive {
@@ -256,7 +252,7 @@ private:
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
math::uint2 attachmentSize = {};
std::vector<wgpu::RenderPassColorAttachment> colorAttachments{};
std::vector<wgpu::RenderPassColorAttachment> colorAttachments {};
};
}// namespace filament::backend

View File

@@ -45,7 +45,6 @@ namespace test {
Backend BackendTest::sBackend = Backend::NOOP;
OperatingSystem BackendTest::sOperatingSystem = OperatingSystem::OTHER;
bool BackendTest::sIsMobilePlatform = false;
std::vector<std::string> BackendTest::sFailedImages;
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform) {
sBackend = backend;
@@ -64,12 +63,11 @@ BackendTest::~BackendTest() {
flushAndWait();
mImageExpectations->evaluate();
// Note: Don't terminate the driver for OpenGL, as it wipes away the context and removes the buffer from the screen.
if (sBackend != Backend::OPENGL) {
driver->terminate();
delete driver;
if (sBackend == Backend::OPENGL) {
return;
}
recordFailedImages();
driver->terminate();
delete driver;
}
void BackendTest::initializeDriver() {
@@ -169,24 +167,8 @@ bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem) {
return sOperatingSystem == operatingSystem;
}
void BackendTest::markImageAsFailure(std::string failedImageName) {
sFailedImages.emplace_back(std::move(failedImageName));
}
void BackendTest::recordFailedImages() {
if (!sFailedImages.empty()) {
std::string failedImages;
for (auto& failedTestImageName: sFailedImages) {
if (failedImages.empty()) {
failedImages = failedTestImageName;
} else {
failedImages.append(",");
failedImages.append(failedTestImageName);
}
}
RecordProperty("FailedImages", failedImages);
}
sFailedImages.clear();
bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem, Backend backend) {
return matchesEnvironment(operatingSystem) && matchesEnvironment(backend);
}
class Environment : public ::testing::Environment {

View File

@@ -38,9 +38,6 @@ public:
static OperatingSystem sOperatingSystem;
static bool sIsMobilePlatform;
// Takes the name of the image that wasn't correct, without the .png suffix
static void markImageAsFailure(std::string failedImageName);
protected:
BackendTest();
@@ -76,13 +73,8 @@ protected:
static bool matchesEnvironment(Backend backend);
static bool matchesEnvironment(OperatingSystem operatingSystem);
static bool matchesEnvironment(OperatingSystem operatingSystem, Backend backend);
private:
// Adds all the images that failed an ImageExpectation to the XML metadata for the current tests
// case. Add --gtest_output=xml as a command line argument to generate a test_detail.xml file in
// the directory where the tests are run.
static void recordFailedImages();
static std::vector<std::string> sFailedImages;
filament::backend::Driver* driver = nullptr;
filament::backend::CommandBufferQueue commandBufferQueue;

View File

@@ -21,7 +21,6 @@
#include "utils/Hash.h"
#include <fstream>
#include "BackendTest.h"
#include "backend/PixelBufferDescriptor.h"
#include "private/backend/DriverApi.h"
@@ -33,8 +32,6 @@
#endif
namespace test {
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
uint32_t expectedHash, bool isSrgb)
: mWidth(width),
@@ -83,10 +80,6 @@ std::string ScreenshotParams::expectedFilePath() const {
return absl::StrFormat("%s/%s", expectedDirectoryPath(), expectedFileName());
}
const std::string ScreenshotParams::filePrefix() const {
return mFileName;
}
ImageExpectation::ImageExpectation(const char* fileName, int lineNumber,
filament::backend::DriverApi& api, ScreenshotParams params,
filament::backend::RenderTargetHandle renderTarget)
@@ -120,11 +113,7 @@ void ImageExpectation::compareImage() const {
#ifndef FILAMENT_IOS
LoadedPng loadedImage(mParams.expectedFilePath());
uint32_t loadedImageHash = loadedImage.hash();
auto compareToImageMatcher = testing::Eq(loadedImageHash);
if (!testing::Matches(compareToImageMatcher)(actualHash)) {
BackendTest::markImageAsFailure(mParams.filePrefix());
}
EXPECT_THAT(actualHash, compareToImageMatcher) << mParams.expectedFileName();
EXPECT_THAT(actualHash, testing::Eq(loadedImageHash)) << mParams.expectedFileName();
#endif
// For builds that can't load PNGs (currently iOS only) use the expected hash.
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash())) << mParams.expectedFileName();
@@ -211,10 +200,6 @@ uint32_t RenderTargetDump::hash() const {
return mInternal->hash();
}
const std::vector<unsigned char>& RenderTargetDump::bytes() const {
return mInternal->bytes;
}
bool RenderTargetDump::bytesFilled() const {
return mInternal->bytesFilled;
}
@@ -252,5 +237,3 @@ uint32_t LoadedPng::hash() const {
const std::vector<unsigned char>& LoadedPng::bytes() const {
return mBytes;
}
} // namespace test

View File

@@ -35,8 +35,6 @@ do { \
screenshotParams); \
} while (0)
namespace test {
/**
* Stores user-provided configuration values for an image expectation
*/
@@ -56,7 +54,6 @@ public:
static std::string expectedDirectoryPath();
std::string expectedFileName() const;
std::string expectedFilePath() const;
const std::string filePrefix() const;
private:
int mWidth;
@@ -85,12 +82,6 @@ public:
* @return The hash of the stored bytes.
*/
uint32_t hash() const;
/**
* Gets the bytes of the render target. The hash should usually be preferable for comparisons
* but this is available for debugging.
* @return The stored bytes.
*/
const std::vector<unsigned char>& bytes() const;
/**
* Thread safe as this is backed by an atomic.
* Once this returns true it will never return false.
@@ -162,6 +153,4 @@ private:
std::vector<std::unique_ptr<ImageExpectation>> mExpectations;
};
} // namespace test
#endif //TNT_IMAGE_EXPECTATIONS_H

View File

@@ -57,7 +57,7 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
if (!kLayouts.empty()) {
mDescriptorSetLayout =
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ .bindings = kLayouts }));
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
}
}

View File

@@ -17,6 +17,7 @@
#include "ShaderGenerator.h"
#include <GlslangToSpv.h>
#include <SPVRemapper.h>
#include <spirv_glsl.hpp>
#include <spirv_msl.hpp>

View File

@@ -32,24 +32,13 @@ do {
} \
} while (false)
#define NONFATAL_FAIL_IF(skipEnvironment, rationale) \
do { \
SkipEnvironment skip(skipEnvironment); \
if (skip.matches()) { \
ADD_FAILURE() \
<< "Failing test as the " << skip.describe() << "\n" \
<< " This test has a known failure where " \
<< rationale; \
} \
} while (false)
#define FAIL_IF(skipEnvironment, rationale) \
do { \
SkipEnvironment skip(skipEnvironment); \
if (skip.matches()) { \
GTEST_FAIL() \
<< "Failing test as the " << skip.describe() << "\n" \
<< " This test should be able to succeed but it needs to fail early because " \
<< " This test should be able to succeed but it needs to fail early because" \
<< rationale; \
} \
} while (false)

View File

@@ -1,153 +1,62 @@
import os, shutil, argparse, typing, xml.etree.ElementTree, subprocess, platform
import os, shutil, argparse, typing
def match_sufffix(file_name: str, suffix: str, accepted_prefixes: typing.List[str]) -> str:
"""
Check if the file name is one of the searched for ones with the given suffix and if so return it.
:param accepted_prefixes: If None accepts any prefix
:return: file_name with the suffix removed or "" if it doesn't match. This does mean a string that
is just the suffix is considered to not match as it will return the empty string.
"""
if file_name.endswith(suffix):
prefix = file_name.removesuffix(suffix)
if accepted_prefixes is None or prefix in accepted_prefixes:
return prefix
return ""
class TestResults(object):
ACTUAL_SUFFIX = '_actual.png'
EXPECTED_SUFFIX = '.png'
def __init__(self, results_directory: str, source_expected_directory: str):
self.results_directory = results_directory
self.actual_directory = os.path.join(self.results_directory, 'images', 'actual_images')
self.expected_directory = os.path.join(self.results_directory, 'images', 'expected_images')
self.source_expected_directory = source_expected_directory
def get_latest_failed_images(self) -> typing.List[str]:
failed_images = []
xml_tree = xml.etree.ElementTree.parse(
os.path.join(self.results_directory, 'test_detail.xml'))
testsuites = xml_tree.getroot()
for testsuite in testsuites.findall('testsuite'):
for testcase in testsuite.findall('testcase'):
for properties in testcase.findall('properties'):
for property in properties.findall('property'):
if property.get('name') == 'FailedImages':
failed_images.extend(property.get('value').split(','))
return failed_images
def handle_failed_image(self, failed_image):
self.show_images(failed_image)
print(f'Update {failed_image}\'s expected image? y/n')
while True:
user_input = input()
if user_input == 'y':
self.move_actual_to_source([failed_image])
break
elif user_input == 'n':
break
def handle_all_failed_images(self):
for failed_image in self.get_latest_failed_images():
self.handle_failed_image(failed_image)
def show_images(self, failed_image):
# TODO: Test more on non-mac systems
open_command: str
os_name = platform.system().lower()
if 'windows' in os_name:
open_command = 'start'
elif 'osx' in os_name or 'darwin' in os_name:
open_command = 'open'
else:
open_command = 'xdg-open'
subprocess.run(
[open_command,
os.path.join(self.actual_directory, failed_image + TestResults.ACTUAL_SUFFIX)])
subprocess.run(
[open_command,
os.path.join(self.expected_directory, failed_image + TestResults.EXPECTED_SUFFIX)])
def move_actual_to_source(self, file_prefixes: typing.List[str]):
replace_file_names(path=self.actual_directory, removed=TestResults.ACTUAL_SUFFIX,
replacement=TestResults.EXPECTED_SUFFIX,
output_path=self.source_expected_directory, prefixes=file_prefixes)
def batch_move(self, prefixes: typing.Optional[typing.List[str]] = None):
replace_file_names(path=self.actual_directory, removed=TestResults.ACTUAL_SUFFIX,
replacement=TestResults.EXPECTED_SUFFIX,
output_path=self.source_expected_directory, prefixes=prefixes)
def match_suffix(file_name: str, suffix: str, accepted_prefixes: typing.List[str]) -> str:
"""
Check if the file name is one of the searched for ones with the given suffix and if so return
it.
:param accepted_prefixes: If None accepts any prefix
:return: file_name with the suffix removed or "" if it doesn't match. This does mean a string
that is just the suffix is considered to not match as it will return the empty string.
"""
if file_name.endswith(suffix):
prefix = file_name.removesuffix(suffix)
if accepted_prefixes is None or prefix in accepted_prefixes:
return prefix
return ''
def replace_file_names(path: str, removed: str, replacement: str = '', output_path: str = '',
prefixes: typing.Optional[typing.List[str]] = None):
if not output_path:
output_path = path
for file_name in os.listdir(path=path):
prefix = match_suffix(file_name, removed, prefixes)
if prefix:
# Remove the prefix from the list so that prefixes is the list of intended but not yet
# found files.
if prefixes is not None:
prefixes.remove(prefix)
new_file_name = prefix + replacement
new_file_path = os.path.join(output_path, new_file_name)
old_file_path = os.path.join(path, file_name)
print(f'{old_file_path} to {new_file_path}')
shutil.copyfile(old_file_path, new_file_path)
if prefixes is not None:
for unfound_prefix in prefixes:
print(f'Failed to find {unfound_prefix}_actual.png')
def replace_file_names(path: str, removed: str, replacement: str = "", output_path: str = "",
prefixes: typing.List[str] = None):
if not output_path:
output_path = path
for file_name in os.listdir(path=path):
prefix = match_sufffix(file_name, removed, prefixes)
if prefix:
# Remove the prefix from the list so that prefixes is the list of intended but not yet found
# files.
if prefixes is not None:
prefixes.remove(prefix)
new_file_name = prefix + replacement
new_file_path = os.path.join(output_path, new_file_name)
old_file_path = os.path.join(path, file_name)
print(f'{old_file_path} to {new_file_path}')
shutil.move(old_file_path, new_file_path)
if prefixes is not None:
for unfound_prefix in prefixes:
print(f'Failed to find {unfound_prefix}_actual.png')
if __name__ == "__main__":
parser = argparse.ArgumentParser(prog='Backend Test File Renamer',
description='Moves actual generated test images to the '
'expected images directory, to update the test '
'requirements. test_cases accepts multiple '
'arguments that should be the name of the '
'expected image file without the .png suffix. '
'Also --all can be passed to copy all images.\n'
'Remember to sync CMake after running this to '
'move the new expected images to the binary '
'directory.')
parser.add_argument('-r', '--results_path',
help='The path with the generated images directory, which should be where '
'the test binary was run.')
parser.add_argument('-s', '--source_expected_path', default="./expected_images",
help='The directory that updated expected images should be written to, '
'which should be the source directory copy.')
# The mutually exclusive options for how to process the actual images
parser.add_argument('-b', '--batch', action='extend', nargs='*',
help='If true copy all actual images to the source expected image '
'directory.')
parser.add_argument('-a', '--all', action='store_true',
help='If true, visually compare all generated images.')
parser.add_argument('-t', '--tests', action='store_true',
help='If true use a test_detail.xml file that exists in the results_path '
'directory to visually compare all images that failed a test.')
parser.add_argument('-c', '--compare', action='extend', nargs='*',
help='A list of image names to visually compare (without the .png suffix).')
parser = argparse.ArgumentParser(prog='Backend Test File Renamer',
description='Moves actual generated test images to the expected '
'images directory, to update the test requirements. '
'test_cases accepts multiple arguments that should '
'be the name of the expected image file without the '
'.png suffix. Also --all can be passed to copy all '
'images.\n'
'Remember to sync CMake after running this to move '
'the new expected images to the binary directory.')
parser.add_argument('-i', '--input_path')
parser.add_argument('-o', '--output_path', default="./expected_images")
parser.add_argument('-t', '--test_cases', action='extend', nargs='*')
parser.add_argument('-a', '--all', action='store_true')
args = parser.parse_args()
if not args.results_path:
raise AssertionError("No result path provided")
results_path = args.results_path
args = parser.parse_args()
input_path = "."
if args.input_path:
input_path = args.input_path
results = TestResults(results_directory=results_path,
source_expected_directory=args.source_expected_path)
prefixes = args.test_cases
if args.all:
prefixes = None
if args.all:
results.batch_move()
elif args.tests:
results.handle_all_failed_images()
elif args.compare:
for file_prefix in args.compare:
results.show_images(file_prefix)
else:
results.batch_move(args.batch)
replace_file_names(path=input_path, output_path=args.output_path, removed="_actual.png",
replacement=".png", prefixes=prefixes)

View File

@@ -260,8 +260,6 @@ TEST_F(BlitTest, ColorMinify) {
}
TEST_F(BlitTest, ColorResolve) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Nothing is drawn, see b/417229577");
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 256;
@@ -492,7 +490,7 @@ TEST_F(BlitTest, BlitRegion) {
}
TEST_F(BlitTest, BlitRegionToSwapChain) {
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment, see b/417481493");
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment");
auto& api = getDriverApi();
mCleanup.addPostCall([&]() { executeCommands(); });

View File

@@ -20,7 +20,6 @@
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
#include "Skip.h"
#include "TrianglePrimitive.h"
namespace test {
@@ -160,8 +159,6 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
// This test renders two triangles in two separate draw calls. Between the draw calls, a uniform
// buffer object is partially updated.
TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"All values including alpha are written as 0, see b/417254943");
auto& api = getDriverApi();
Cleanup cleanup(api);

View File

@@ -26,7 +26,6 @@ namespace test {
TEST_F(BackendTest, FrameScheduledCallback) {
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -86,7 +85,6 @@ TEST_F(BackendTest, FrameScheduledCallback) {
TEST_F(BackendTest, FrameCompletedCallback) {
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
auto& api = getDriverApi();
Cleanup cleanup(api);

View File

@@ -99,8 +99,6 @@ struct MaterialParams {
// The problems are caused by both uploading and rendering into the same texture, since the OpenGL
// backend's readPixels does not work correctly with textures that have image data uploaded.
TEST_F(BackendTest, FeedbackLoops) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Image is unexpectedly darker, see b/417226296");
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL),
"OpenGL image is upside down due to readPixels failing for texture with uploaded image "
"data");

View File

@@ -212,7 +212,7 @@ static SamplerFormat getSamplerFormat(TextureFormat textureFormat) {
}
TEST_F(LoadImageTest, UpdateImage2D) {
FAIL_IF(Backend::VULKAN, "Multiple test cases crash, see b/417481434");
FAIL_IF(Backend::VULKAN, "Multiple test cases crash");
// All of these test cases should result in the same rendered image, and thus the same hash.
static const uint32_t expectedHash = 3644679986;
@@ -485,9 +485,6 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
}
TEST_F(LoadImageTest, UpdateImage3D) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Checkerboard not drawn, possibly due to using wrong z value of 3d texture, "
"see b/417254499");
auto& api = getDriverApi();
Cleanup cleanup(api);
api.startCapture();

View File

@@ -81,8 +81,7 @@ void main() {
TEST_F(BackendTest, PushConstants) {
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
FAIL_IF(Backend::VULKAN,
"Crashing due to no program set when setting push constants, see b/417477740");
FAIL_IF(Backend::VULKAN, "Crashing due to no program set when setting push constants");
auto& api = getDriverApi();

View File

@@ -20,7 +20,6 @@
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
#include "Skip.h"
#include "TrianglePrimitive.h"
#include <utils/Hash.h>
@@ -75,8 +74,6 @@ public:
};
TEST_F(ReadPixelsTest, ReadPixels) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Two cases fail, see b/417255941 and b/417255943");
// These test scenarios use a known hash of the result pixel buffer to decide pass / fail,
// asserting an exact pixel-for-pixel match. So far, rendering on macOS and iPhone have had
// deterministic results. Take this test with a grain of salt, however, as other platform / GPU

View File

@@ -20,7 +20,6 @@
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
#include "Skip.h"
#include "TrianglePrimitive.h"
#include <utils/Hash.h>
@@ -31,8 +30,6 @@ using namespace filament;
using namespace filament::backend;
TEST_F(BackendTest, ScissorViewportRegion) {
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Affected area in wrong corner, see b/417229118");
auto& api = getDriverApi();
constexpr int kSrcTexWidth = 1024;

View File

@@ -117,8 +117,6 @@ public:
};
TEST_F(BasicStencilBufferTest, StencilBuffer) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Stencil not supported, see b/417230776");
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -141,8 +139,6 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
}
TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Stencil not supported, see b/417230776");
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -166,8 +162,6 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
}
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Stencil not supported, see b/417230776");
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL), "Stencil isn't applied");
auto& api = getDriverApi();
Cleanup cleanup(api);

View File

@@ -21,6 +21,7 @@
#include <backend/CallbackHandler.h>
#include <backend/DriverEnums.h>
#include <backend/PresentCallable.h>
#include <utils/compiler.h>
#include <utils/Invocable.h>
@@ -34,7 +35,7 @@ class Engine;
/**
* A swap chain represents an Operating System's *native* renderable surface.
*
* Typically, it's a native window or a view. Because a SwapChain is initialized from a
* Typically it's a native window or a view. Because a SwapChain is initialized from a
* native object, it is given to filament as a `void *`, which must be of the proper type
* for each platform filament is running on.
*
@@ -157,7 +158,7 @@ public:
/**
* Requests a SwapChain with an alpha channel.
*/
static constexpr uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT;
static const uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT;
/**
* This flag indicates that the swap chain may be used as a source surface
@@ -167,13 +168,13 @@ public:
* @see
* Renderer.copyFrame()
*/
static constexpr uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE;
static const uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE;
/**
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
*/
static constexpr uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB;
static const uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB;
/**
* Indicates that the native window is a CVPixelBufferRef.
@@ -185,7 +186,7 @@ public:
* Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and
* CVPixelBufferRelease when the swap chain is destroyed.
*/
static constexpr uint64_t CONFIG_APPLE_CVPIXELBUFFER =
static const uint64_t CONFIG_APPLE_CVPIXELBUFFER =
backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER;
/**
@@ -302,7 +303,6 @@ public:
*
* @param handler Handler to dispatch the callback or nullptr for the default handler.
* @param callback Callback called when the frame is scheduled.
* @param flags
*
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
* backends ignore the callback (which will never be called) and proceed normally.
@@ -314,7 +314,7 @@ public:
FrameScheduledCallback&& callback = {}, uint64_t flags = 0);
/**
* Returns whether this SwapChain currently has a FrameScheduledCallback set.
* Returns whether or not this SwapChain currently has a FrameScheduledCallback set.
*
* @return true, if the last call to setFrameScheduledCallback set a callback
*

View File

@@ -16,22 +16,13 @@
#include "AtlasAllocator.h"
#include <utils/compiler.h>
#include <utils/algorithm.h>
#include <utils/debug.h>
#include <utils/QuadTree.h>
#include <algorithm>
#include <utility>
#include <stddef.h>
#include <stdint.h>
namespace filament {
using namespace utils;
static constexpr std::pair<uint8_t, uint8_t> unmorton(uint16_t const m) noexcept {
static inline constexpr std::pair<uint8_t, uint8_t> unmorton(uint16_t const m) noexcept {
uint32_t r = (m | (uint32_t(m) << 15u)) & 0x55555555u;
r = (r | (r >> 1u)) & 0x33333333u;
r = (r | (r >> 2u)) & 0x0f0f0f0fu;
@@ -174,8 +165,8 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t const maxHeight) n
NodeId found{ -1, 0 };
QuadTree::traverse(candidate.l, candidate.code,
[this, n, &found](NodeId const& curr) -> QuadTree::TraversalResult {
size_t const j = index(curr.l, curr.code);
Node& node = mQuadTree[j];
size_t const i = index(curr.l, curr.code);
Node& node = mQuadTree[i];
if (curr.l == n) {
found = curr;
assert_invariant(!node.hasChildren());

View File

@@ -648,32 +648,44 @@ bool ChunkAttributeInfo::unflatten(Unflattener& unflattener,
bool ChunkDescriptorBindingsInfo::unflatten(Unflattener& unflattener,
MaterialParser::DescriptorBindingsContainer* container) {
static_assert(sizeof(DescriptorSetBindingPoints) == sizeof(uint8_t));
uint8_t descriptorCount;
if (!unflattener.read(&descriptorCount)) {
uint8_t setCount;
if (!unflattener.read(&setCount)) {
return false;
}
auto& descriptors = (*container)[+DescriptorSetBindingPoints::PER_MATERIAL];
descriptors.reserve(descriptorCount);
for (size_t i = 0; i < descriptorCount; i++) {
CString name;
if (!unflattener.read(&name)) {
for (size_t j = 0; j < setCount; j++) {
static_assert(sizeof(DescriptorSetBindingPoints) == sizeof(uint8_t));
DescriptorSetBindingPoints set;
if (!unflattener.read(reinterpret_cast<uint8_t*>(&set))) {
return false;
}
uint8_t type;
if (!unflattener.read(&type)) {
uint8_t descriptorCount;
if (!unflattener.read(&descriptorCount)) {
return false;
}
uint8_t binding;
if (!unflattener.read(&binding)) {
return false;
auto& descriptors = (*container)[+set];
descriptors.reserve(descriptorCount);
for (size_t i = 0; i < descriptorCount; i++) {
CString name;
if (!unflattener.read(&name)) {
return false;
}
uint8_t type;
if (!unflattener.read(&type)) {
return false;
}
uint8_t binding;
if (!unflattener.read(&binding)) {
return false;
}
descriptors.push_back({
std::move(name),
DescriptorType(type),
descriptor_binding_t(binding)});
}
descriptors.push_back({
std::move(name),
DescriptorType(type),
descriptor_binding_t(binding)});
}
return true;
@@ -681,40 +693,42 @@ bool ChunkDescriptorBindingsInfo::unflatten(Unflattener& unflattener,
bool ChunkDescriptorSetLayoutInfo::unflatten(Unflattener& unflattener,
MaterialParser::DescriptorSetLayoutContainer* container) {
uint8_t descriptorCount;
if (!unflattener.read(&descriptorCount)) {
return false;
}
auto& descriptors = container->bindings;
descriptors.reserve(descriptorCount);
for (size_t i = 0; i < descriptorCount; i++) {
uint8_t type;
if (!unflattener.read(&type)) {
for (size_t j = 0; j < 2; j++) {
uint8_t descriptorCount;
if (!unflattener.read(&descriptorCount)) {
return false;
}
uint8_t stageFlags;
if (!unflattener.read(&stageFlags)) {
return false;
auto& descriptors = (*container)[j].bindings;
descriptors.reserve(descriptorCount);
for (size_t i = 0; i < descriptorCount; i++) {
uint8_t type;
if (!unflattener.read(&type)) {
return false;
}
uint8_t stageFlags;
if (!unflattener.read(&stageFlags)) {
return false;
}
uint8_t binding;
if (!unflattener.read(&binding)) {
return false;
}
uint8_t flags;
if (!unflattener.read(&flags)) {
return false;
}
uint16_t count;
if (!unflattener.read(&count)) {
return false;
}
descriptors.push_back({
DescriptorType(type),
ShaderStageFlags(stageFlags),
descriptor_binding_t(binding),
DescriptorFlags(flags),
count,
});
}
uint8_t binding;
if (!unflattener.read(&binding)) {
return false;
}
uint8_t flags;
if (!unflattener.read(&flags)) {
return false;
}
uint16_t count;
if (!unflattener.read(&count)) {
return false;
}
descriptors.push_back({
DescriptorType(type),
ShaderStageFlags(stageFlags),
descriptor_binding_t(binding),
DescriptorFlags(flags),
count,
});
}
return true;
}

View File

@@ -93,7 +93,7 @@ public:
using DescriptorBindingsContainer = backend::Program::DescriptorSetInfo;
bool getDescriptorBindings(DescriptorBindingsContainer* container) const noexcept;
using DescriptorSetLayoutContainer = backend::DescriptorSetLayout;
using DescriptorSetLayoutContainer = std::array<backend::DescriptorSetLayout, 2>;
bool getDescriptorSetLayout(DescriptorSetLayoutContainer* container) const noexcept;
bool getDepthWriteSet(bool* value) const noexcept;

View File

@@ -609,12 +609,9 @@ Program FMaterial::getProgramWithVariants(
program.attributes(mAttributeInfo);
}
program.descriptorBindings(+DescriptorSetBindingPoints::PER_VIEW,
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_VIEW]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_RENDERABLE,
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_RENDERABLE]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_MATERIAL,
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_MATERIAL]);
program.descriptorBindings(0, mProgramDescriptorBindings[0]);
program.descriptorBindings(1, mProgramDescriptorBindings[1]);
program.descriptorBindings(2, mProgramDescriptorBindings[2]);
program.specializationConstants(mSpecializationConstants);
program.pushConstants(ShaderStage::VERTEX, mPushConstants[uint8_t(ShaderStage::VERTEX)]);
@@ -1143,45 +1140,37 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* const parser) {
UTILS_UNUSED_IN_RELEASE bool success;
success = parser->getDescriptorBindings(&mProgramDescriptorBindings);
assert_invariant(success);
backend::DescriptorSetLayout descriptorSetLayout;
std::array<backend::DescriptorSetLayout, 2> descriptorSetLayout;
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
assert_invariant(success);
auto perMatLabel = mName;
perMatLabel.append("_perMat");
descriptorSetLayout.label = std::move(perMatLabel);
// get the PER_VIEW descriptor binding info
auto perViewDescriptorSetLayout =
descriptor_sets::getPerViewDescriptorSetLayout(mMaterialDomain, mVariantFilterMask,
mIsVariantLit || mHasShadowMultiplier, mReflectionMode, mRefractionMode);
auto perViewLabel = mName;
perViewLabel.append("_perView");
perViewDescriptorSetLayout.label = std::move(perViewLabel);
// Setup Labels for debugging
utils::CString namestr;
utils::StaticString perViewStr = "_perView";
utils::StaticString singleStr = "_single";
// get the PER_RENDERABLE and PER_VIEW descriptor binding info
for (auto&& [bindingPoint, descriptorSetLayout] : {
std::pair{ DescriptorSetBindingPoints::PER_RENDERABLE,
descriptor_sets::getPerRenderableLayout() },
std::pair{ DescriptorSetBindingPoints::PER_VIEW,
perViewDescriptorSetLayout }}) {
Program::DescriptorBindingsInfo& descriptors = mProgramDescriptorBindings[+bindingPoint];
descriptors.reserve(descriptorSetLayout.bindings.size());
for (auto const& entry: descriptorSetLayout.bindings) {
auto const& name = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
descriptors.push_back({ name, entry.type, entry.binding });
}
}
parser->getName(&namestr);
utils::CString singleLabel(namestr.c_str(), namestr.length() + singleStr.length());
memccpy(singleLabel.c_str() + namestr.length(), singleStr.c_str(), '\0', singleStr.length());
utils::CString perViewLabel(namestr.c_str(), namestr.length() + perViewStr.length());
memccpy(perViewLabel.c_str() + namestr.length(), perViewStr.c_str(), '\0', perViewStr.length());
descriptorSetLayout[0].label = namestr;
descriptorSetLayout[1].label = perViewLabel;
mDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(descriptorSetLayout) };
engine.getDriverApi(), std::move(descriptorSetLayout[0]) };
mPerViewDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), perViewDescriptorSetLayout };
engine.getDriverApi(), std::move(descriptorSetLayout[1]) };
}
descriptor_binding_t FMaterial::getSamplerBinding(

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.60.0"
spec.version = "1.59.4"
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.60.0/filament-v1.60.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.4/filament-v1.59.4-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -102,8 +102,7 @@ project in Xcode to see changes take effect.
## Building iOS Samples with ASan / UBSan
1. Turn on ASan / UBSan in Filament's top-level CMakeLists.txt by passing
`-DFILAMENT_ENABLE_ASAN_UBSAN=1` to trigger the following line:
1. Turn on ASan / UBSan in Filament's top-level CMakeLists.txt by uncommenting the following line:
```
set(EXTRA_SANITIZE_OPTIONS "-fsanitize=undefined -fsanitize=address")

View File

@@ -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 = 60;
static constexpr size_t MATERIAL_VERSION = 59;
/**
* Supported shading models

View File

@@ -20,7 +20,6 @@
#include <backend/DriverEnums.h>
#include <private/filament/EngineEnums.h>
#include <private/filament/Variant.h>
#include <filament/MaterialEnums.h>
@@ -40,16 +39,8 @@ backend::DescriptorSetLayout getPerViewDescriptorSetLayout(
ReflectionMode reflectionMode,
RefractionMode refractionMode) noexcept;
backend::DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
Variant variant,
MaterialDomain domain,
UserVariantFilterMask variantFilter,
bool isLit,
ReflectionMode reflectionMode,
RefractionMode refractionMode) noexcept;
utils::CString getDescriptorName(
DescriptorSetBindingPoints set,
filament::DescriptorSetBindingPoints set,
backend::descriptor_binding_t binding) noexcept;
} // namespace filament::descriptor_sets

View File

@@ -23,8 +23,6 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <private/filament/DescriptorSets.h>
#include <initializer_list>
#include <unordered_map>
#include <string_view>
@@ -52,7 +50,6 @@ public:
using Precision = backend::Precision;
using SamplerParams = backend::SamplerParams;
using Binding = backend::descriptor_binding_t;
using ShaderStageFlags = backend::ShaderStageFlags;
struct SamplerInfo { // NOLINT(cppcoreguidelines-pro-type-member-init)
utils::CString name; // name of this sampler
@@ -62,7 +59,6 @@ public:
Format format; // format of this sampler
Precision precision; // precision of this sampler
bool multisample; // multisample capable
ShaderStageFlags stages; // stages the sampler can be accessed from
};
using SamplerInfoList = utils::FixedCapacityVector<SamplerInfo>;
@@ -84,8 +80,6 @@ public:
Format format; // format of this sampler
Precision precision; // precision of this sampler
bool multisample = false; // multisample capable
ShaderStageFlags stages =
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS; // shader stages using this sampler
};
// Give a name to this sampler interface block
@@ -95,8 +89,8 @@ public:
// Add a sampler
Builder& add(std::string_view samplerName, Binding binding, Type type, Format format,
Precision precision = Precision::MEDIUM, bool multisample = false,
ShaderStageFlags stages = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) noexcept;
Precision precision = Precision::MEDIUM,
bool multisample = false) noexcept;
// Add multiple samplers
Builder& add(std::initializer_list<ListEntry> list) noexcept;
@@ -134,9 +128,6 @@ public:
static utils::CString generateUniformName(const char* group, const char* sampler) noexcept;
static SamplerInfoList filterSamplerList(SamplerInfoList list,
backend::DescriptorSetLayout const& descriptorSetLayout);
private:
friend class Builder;

View File

@@ -17,7 +17,6 @@
#include "private/filament/DescriptorSets.h"
#include <private/filament/EngineEnums.h>
#include <private/filament/Variant.h>
#include <filament/MaterialEnums.h>
@@ -27,35 +26,38 @@
#include <utils/debug.h>
#include <algorithm>
#include <initializer_list>
#include <string_view>
#include <unordered_map>
#include <string_view>
namespace filament::descriptor_sets {
using namespace backend;
static constexpr std::initializer_list<DescriptorSetLayoutBinding> postProcessDescriptorSetLayoutList = {
static DescriptorSetLayout const postProcessDescriptorSetLayout{
utils::StaticString("postProcess"),{
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
};
}};
static constexpr std::initializer_list<DescriptorSetLayoutBinding> depthVariantDescriptorSetLayoutList = {
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
utils::StaticString("depthVariant"),{
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
};
}};
// 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 constexpr std::initializer_list<DescriptorSetLayoutBinding> ssrVariantDescriptorSetLayoutList = {
{ 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{
utils::StaticString("ssrVariant"),{
{ 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 constexpr std::initializer_list<DescriptorSetLayoutBinding> perViewDescriptorSetLayoutList = {
static DescriptorSetLayout perViewDescriptorSetLayout = {
utils::StaticString("perView"),{
{ 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 },
@@ -68,37 +70,17 @@ static constexpr std::initializer_list<DescriptorSetLayoutBinding> perViewDescri
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSAO },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
};
}};
static constexpr std::initializer_list<DescriptorSetLayoutBinding> perRenderableDescriptorSetLayoutList = {
static DescriptorSetLayout perRenderableDescriptorSetLayout = {
utils::StaticString("perRenderable"),{
{ 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 },
};
// used for post-processing passes
static DescriptorSetLayout const postProcessDescriptorSetLayout{ utils::StaticString("postProcess"),
postProcessDescriptorSetLayoutList };
// used to generate shadow-maps
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
utils::StaticString("depthVariant"), depthVariantDescriptorSetLayoutList
};
static DescriptorSetLayout const ssrVariantDescriptorSetLayout{ utils::StaticString("ssrVariant"),
ssrVariantDescriptorSetLayoutList };
// Used for generating the color pass (i.e. the main pass). This is in fact a template that gets
// declined into 8 different layouts, based on variants.
static DescriptorSetLayout perViewDescriptorSetLayout = { utils::StaticString("perView"),
perViewDescriptorSetLayoutList };
static DescriptorSetLayout perRenderableDescriptorSetLayout = {
utils::StaticString("perRenderable"), perRenderableDescriptorSetLayoutList
};
}};
DescriptorSetLayout const& getPostProcessLayout() noexcept {
return postProcessDescriptorSetLayout;
@@ -116,8 +98,8 @@ DescriptorSetLayout const& getPerRenderableLayout() noexcept {
return perRenderableDescriptorSetLayout;
}
utils::CString getDescriptorName(DescriptorSetBindingPoints const set,
descriptor_binding_t const binding) 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{{
@@ -163,11 +145,11 @@ utils::CString getDescriptorName(DescriptorSetBindingPoints const set,
}
DescriptorSetLayout getPerViewDescriptorSetLayout(
MaterialDomain const domain,
UserVariantFilterMask const variantFilter,
bool const isLit,
ReflectionMode const reflectionMode,
RefractionMode const refractionMode) noexcept {
MaterialDomain domain,
UserVariantFilterMask variantFilter,
bool isLit,
ReflectionMode reflectionMode,
RefractionMode refractionMode) noexcept {
bool const ssr = reflectionMode == ReflectionMode::SCREEN_SPACE ||
refractionMode == RefractionMode::SCREEN_SPACE;
@@ -210,65 +192,11 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
return layout;
}
case MaterialDomain::POST_PROCESS:
return postProcessDescriptorSetLayout;
return descriptor_sets::getPostProcessLayout();
case MaterialDomain::COMPUTE:
// TODO: what's the layout for compute?
return postProcessDescriptorSetLayout;
return descriptor_sets::getPostProcessLayout();
}
}
DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
Variant const variant,
MaterialDomain domain,
UserVariantFilterMask const variantFilter,
bool const isLit,
ReflectionMode const reflectionMode,
RefractionMode const refractionMode) noexcept {
if (Variant::isValidDepthVariant(variant)) {
return depthVariantDescriptorSetLayout;
}
if (Variant::isSSRVariant(variant)) {
return ssrVariantDescriptorSetLayout;
}
// We need to filter out all the descriptors not included in the "resolved" layout below
return getPerViewDescriptorSetLayout(domain, variantFilter,
isLit, reflectionMode, refractionMode);
}
template<class ITERATOR, class PREDICATE>
constexpr static ITERATOR find_if(ITERATOR first, ITERATOR last, PREDICATE pred) {
for (; first != last; ++first)
if (pred(*first)) break;
return first;
}
constexpr static bool checkConsistency() noexcept {
// check that all descriptors that apply to the vertex stage in perViewDescriptorSetLayout
// are present in ssrVariantDescriptorSetLayout; meaning that the latter is compatible
// with the former.
for (auto const& r: perViewDescriptorSetLayoutList) {
if (hasShaderType(r.stageFlags, ShaderStage::VERTEX)) {
auto const pos = find_if(
ssrVariantDescriptorSetLayoutList.begin(),
ssrVariantDescriptorSetLayoutList.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;
});
if (pos == ssrVariantDescriptorSetLayoutList.end()) {
return false;
}
}
}
return true;
}
static_assert(checkConsistency(), "ssrVariantDescriptorSetLayout is not compatible with "
"perViewDescriptorSetLayout");
} // namespace filament::descriptor_sets

View File

@@ -16,7 +16,6 @@
#include "private/filament/SamplerInterfaceBlock.h"
#include <private/filament/DescriptorSets.h>
#include <backend/DriverEnums.h>
@@ -49,13 +48,13 @@ SamplerInterfaceBlock::Builder::stageFlags(backend::ShaderStageFlags stageFlags)
return *this;
}
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(std::string_view samplerName,
Binding binding, Type type, Format format, Precision precision, bool multisample,
ShaderStageFlags stages) noexcept {
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
std::string_view samplerName, Binding binding, Type type, Format format,
Precision precision, bool multisample) noexcept {
mEntries.push_back({
{ samplerName.data(), samplerName.size() }, // name
{ }, // uniform name
binding, type, format, precision, multisample, stages });
binding, type, format, precision, multisample });
return *this;
}
@@ -66,7 +65,7 @@ SamplerInterfaceBlock SamplerInterfaceBlock::Builder::build() {
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
std::initializer_list<ListEntry> list) noexcept {
for (auto& e : list) {
add(e.name, e.binding, e.type, e.format, e.precision, e.multisample, e.stages);
add(e.name, e.binding, e.type, e.format, e.precision, e.multisample);
}
return *this;
}
@@ -91,7 +90,6 @@ SamplerInterfaceBlock::SamplerInterfaceBlock(Builder const& builder) noexcept
size_t const i = std::distance(builder.mEntries.data(), &e);
SamplerInfo& info = samplersInfoList[i];
info = e;
info.stages &= builder.mStageFlags;
info.uniformName = generateUniformName(mName.c_str(), e.name.c_str());
infoMap[{ info.name.data(), info.name.size() }] = i; // info.name.c_str() guaranteed constant
}
@@ -104,7 +102,7 @@ const SamplerInterfaceBlock::SamplerInfo* SamplerInterfaceBlock::getSamplerInfo(
return &mSamplersInfoList[pos->second];
}
CString SamplerInterfaceBlock::generateUniformName(const char* group, const char* sampler) noexcept {
utils::CString SamplerInterfaceBlock::generateUniformName(const char* group, const char* sampler) noexcept {
char uniformName[256];
// sampler interface block name
@@ -119,27 +117,9 @@ CString SamplerInterfaceBlock::generateUniformName(const char* group, const char
std::min(sizeof(uniformName) / 2 - 2, strlen(sampler)),
prefix + 1);
*last++ = 0; // null terminator
assert_invariant(last <= std::end(uniformName));
assert(last <= std::end(uniformName));
return CString{ uniformName, size_t(last - uniformName) - 1u };
}
SamplerInterfaceBlock::SamplerInfoList SamplerInterfaceBlock::filterSamplerList(
SamplerInfoList list, backend::DescriptorSetLayout const& descriptorSetLayout) {
// remove all the samplers that are not included in the descriptor-set layout
list.erase(
std::remove_if(list.begin(), list.end(),
[&](auto const& entry) {
auto pos = std::find_if(
descriptorSetLayout.bindings.begin(),
descriptorSetLayout.bindings.end(),
[&entry](const auto& item) {
return item.binding == entry.binding;
});
return pos == descriptorSetLayout.bindings.end();
}), list.end());
return list;
}
} // namespace filament

View File

@@ -56,7 +56,6 @@ set(PRIVATE_HDRS
src/MetalArgumentBuffer.h
src/ShaderMinifier.h
src/SpirvFixup.h
src/SpirvRemapWrapper.h
src/sca/ASTHelpers.h
src/sca/GLSLTools.h
src/sca/builtinResource.h)
@@ -72,8 +71,7 @@ set(SRCS
src/sca/GLSLTools.cpp
src/GLSLPostProcessor.cpp
src/ShaderMinifier.cpp
src/SpirvFixup.cpp
src/SpirvRemapWrapper.cpp)
src/SpirvFixup.cpp)
# ==================================================================================================
# Include and target definitions

View File

@@ -35,7 +35,6 @@ using OutputTarget = MaterialBuilder::OutputTarget;
using OutputQualifier = MaterialBuilder::VariableQualifier;
using OutputType = MaterialBuilder::OutputType;
using ConstantType = MaterialBuilder::ConstantType;
using ShaderStageType = MaterialBuilder::ShaderStageFlags;
// Convenience methods to convert std::string to Enum and also iterate over Enum values.
class Enums {
@@ -80,7 +79,6 @@ private:
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
static std::unordered_map<std::string, OutputType> mStringToOutputType;
static std::unordered_map<std::string, ConstantType> mStringToConstantType;
static std::unordered_map<std::string, ShaderStageType> mStringToShaderStageType;
};
template<typename T>

View File

@@ -254,7 +254,6 @@ public:
using FeatureLevel = filament::backend::FeatureLevel;
using StereoscopicType = filament::backend::StereoscopicType;
using ShaderStage = filament::backend::ShaderStage;
using ShaderStageFlags = filament::backend::ShaderStageFlags;
enum class VariableQualifier : uint8_t {
OUT
@@ -323,9 +322,9 @@ public:
*/
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
SamplerFormat format = SamplerFormat::FLOAT,
ParameterPrecision precision = ParameterPrecision::DEFAULT, bool multisample = false,
const char* transformName = "",
ShaderStageFlags stages = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) noexcept;
ParameterPrecision precision = ParameterPrecision::DEFAULT,
bool multisample = false,
const char* transformName = "") noexcept;
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
@@ -604,7 +603,7 @@ public:
* extension will be derived from the shader stage. For example, mymaterial_0x0e.frag,
* mymaterial_0x18.vert, etc.
*/
MaterialBuilder& saveRawVariants(bool saveRawVariants) noexcept;
MaterialBuilder& saveRawVariants(bool saveVariants) noexcept;
//! If true, will include debugging information in generated SPIRV.
MaterialBuilder& generateDebugInfo(bool generateDebugInfo) noexcept;
@@ -636,7 +635,7 @@ public:
* Build the material. If you are using the Filament engine with this library, you should use
* the job system provided by Engine.
*/
Package build(utils::JobSystem& jobSystem);
Package build(utils::JobSystem& jobSystem) noexcept;
public:
// The methods and types below are for internal use
@@ -657,10 +656,8 @@ public:
Parameter() noexcept: parameterType(INVALID) {}
// Sampler
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p,
bool ms, const char* tn, ShaderStageFlags s)
: name(paramName), size(1), precision(p), samplerType(t), format(f),
parameterType(SAMPLER), multisample(ms), transformName(tn), stages(s) { }
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms, const char* tn)
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms), transformName(tn) { }
// Uniform
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
@@ -679,7 +676,6 @@ public:
SamplerFormat format;
bool multisample;
utils::CString transformName;
ShaderStageFlags stages;
enum {
INVALID,
UNIFORM,
@@ -813,7 +809,7 @@ private:
// Multiple calls to findProperties accumulate the property sets across fragment
// and vertex shaders in mProperties.
bool findProperties(filament::backend::ShaderStage type,
MaterialBuilder::PropertyList const& allProperties,
MaterialBuilder::PropertyList& allProperties,
CodeGenParams const& semanticCodeGenParams) noexcept;
bool runSemanticAnalysis(MaterialInfo* inOutInfo,

View File

@@ -175,15 +175,4 @@ std::unordered_map<std::string, ConstantType>& Enums::getMap<ConstantType>() noe
return mStringToConstantType;
};
std::unordered_map<std::string, ShaderStageType> Enums::mStringToShaderStageType = {
{ "fragment", ShaderStageType::FRAGMENT },
{ "vertex", ShaderStageType::VERTEX },
{ "compute", ShaderStageType::COMPUTE },
};
template <>
std::unordered_map<std::string, ShaderStageType>& Enums::getMap<ShaderStageType>() noexcept {
return mStringToShaderStageType;
};
} // namespace filamat

View File

@@ -17,6 +17,7 @@
#include "GLSLPostProcessor.h"
#include <GlslangToSpv.h>
#include <SPVRemapper.h>
#include <spirv-tools/libspirv.hpp>
#include <spirv_glsl.hpp>
@@ -33,19 +34,14 @@
#include "MetalArgumentBuffer.h"
#include "SpirvFixup.h"
#include "utils/ostream.h"
#include <filament/MaterialEnums.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <algorithm>
#include <optional>
#include <sstream>
#include <unordered_map>
#include <utility>
#include <vector>
#ifdef FILAMENT_SUPPORTS_WEBGPU
@@ -144,27 +140,32 @@ DescriptorSetLayout getPerMaterialDescriptorSet(SamplerInterfaceBlock const& sib
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
+PerMaterialBindingPoints::MATERIAL_PARAMS, DescriptorFlags::NONE, 0 });
for (auto const& sampler: samplers) {
layout.bindings.push_back(DescriptorSetLayoutBinding{
(sampler.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL)
? DescriptorType::SAMPLER_EXTERNAL
: DescriptorType::SAMPLER,
sampler.stages, sampler.binding, DescriptorFlags::NONE, 0 });
for (auto const& sampler : samplers) {
layout.bindings.push_back(DescriptorSetLayoutBinding {
(sampler.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) ?
DescriptorType::SAMPLER_EXTERNAL : DescriptorType::SAMPLER,
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, sampler.binding,
DescriptorFlags::NONE, 0 });
}
return layout;
}
static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
static void collectDescriptorsForSet(filament::DescriptorSetBindingPoints set,
const GLSLPostProcessor::Config& config, DescriptorSetInfo& descriptors) {
const MaterialInfo& material = *config.materialInfo;
// get the descriptor set layout for the given pinding point
DescriptorSetLayout const descriptorSetLayout = [&] {
DescriptorSetLayout const info = [&]() {
switch (set) {
case DescriptorSetBindingPoints::PER_VIEW: {
return descriptor_sets::getPerViewDescriptorSetLayoutWithVariant(
config.variant, config.domain, config.variantFilter,
if (filament::Variant::isValidDepthVariant(config.variant)) {
return descriptor_sets::getDepthVariantLayout();
}
if (filament::Variant::isSSRVariant(config.variant)) {
return descriptor_sets::getSsrVariantLayout();
}
return descriptor_sets::getPerViewDescriptorSetLayout(config.domain,
config.variantFilter,
material.isLit || material.hasShadowMultiplier,
material.reflectionMode,
material.refractionMode);
@@ -178,8 +179,7 @@ static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
}
}();
// get the sampler list for this binding point
auto samplerList = [&] {
auto samplerList = [&]() {
switch (set) {
case DescriptorSetBindingPoints::PER_VIEW:
return SibGenerator::getPerViewSib(config.variant).getSamplerInfoList();
@@ -192,34 +192,42 @@ static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
}
}();
// filter the list with the descriptor set layout
auto const descriptorSetSamplerList =
SamplerInterfaceBlock::filterSamplerList(std::move(samplerList), descriptorSetLayout);
// remove all the samplers that are not included in the descriptor-set layout
samplerList.erase(std::remove_if(samplerList.begin(), samplerList.end(),
[&info](auto const& entry) {
auto pos = std::find_if(info.bindings.begin(),
info.bindings.end(), [&entry](const auto& item) {
return item.binding == entry.binding;
});
return pos == info.bindings.end();
}),
samplerList.end());
// helper to get the name of a descriptor for this set, given a binding.
auto getDescriptorName = [set, &descriptorSetSamplerList](descriptor_binding_t binding) {
auto getDescriptorName = [&](DescriptorSetBindingPoints set, descriptor_binding_t binding) {
if (set == DescriptorSetBindingPoints::PER_MATERIAL) {
auto pos = std::find_if(descriptorSetSamplerList.begin(), descriptorSetSamplerList.end(),
auto pos = std::find_if(samplerList.begin(), samplerList.end(),
[&](const auto& entry) { return entry.binding == binding; });
if (pos == descriptorSetSamplerList.end()) {
if (pos == samplerList.end()) {
return descriptor_sets::getDescriptorName(set, binding);
}
return pos->uniformName;
SamplerInterfaceBlock::SamplerInfo& sampler = *pos;
return sampler.uniformName;
}
return descriptor_sets::getDescriptorName(set, binding);
};
for (auto descriptor : descriptorSetLayout.bindings) {
descriptor_binding_t binding = descriptor.binding;
auto name = getDescriptorName(binding);
if (descriptor.type == DescriptorType::SAMPLER ||
descriptor.type == DescriptorType::SAMPLER_EXTERNAL) {
auto pos = std::find_if(descriptorSetSamplerList.begin(), descriptorSetSamplerList.end(),
for (size_t i = 0; i < info.bindings.size(); i++) {
backend::descriptor_binding_t binding = info.bindings[i].binding;
auto name = getDescriptorName(set, binding);
if (info.bindings[i].type == DescriptorType::SAMPLER ||
info.bindings[i].type == DescriptorType::SAMPLER_EXTERNAL) {
auto pos = std::find_if(samplerList.begin(), samplerList.end(),
[&](const auto& entry) { return entry.binding == binding; });
assert_invariant(pos != descriptorSetSamplerList.end());
descriptors.emplace_back(name, descriptor, *pos);
assert_invariant(pos != samplerList.end());
SamplerInterfaceBlock::SamplerInfo& sampler = *pos;
descriptors.emplace_back(name, info.bindings[i], sampler);
} else {
descriptors.emplace_back(name, descriptor, std::nullopt);
descriptors.emplace_back(name, info.bindings[i], std::nullopt);
}
}
@@ -288,8 +296,24 @@ GLSLPostProcessor::GLSLPostProcessor(MaterialBuilder::Optimization optimization,
: mOptimization(optimization),
mPrintShaders(flags & PRINT_SHADERS),
mGenerateDebugInfo(flags & GENERATE_DEBUG_INFO) {
// This should occur only once, to avoid races.
SpirvRemapWrapperSetUp();
// SPIRV error handler registration needs to occur only once. To avoid a race we do it up here
// in the constructor, which gets invoked before MaterialBuilder kicks off jobs.
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
slog.e << str << io::endl;
});
// Similar to above, we need to do a no-op remap to init a static table in the remapper before
// the jobs start using remap().
spv::spirvbin_t remapper(0);
// We need to provide at least a valid header to not crash.
SpirvBlob spirv {
0x07230203,// MAGIC
0, // VERSION
0, // GENERATOR
0, // BOUND
0 // SCHEMA, must be 0
};
remapper.remap(spirv, 0);
}
GLSLPostProcessor::~GLSLPostProcessor() = default;
@@ -341,7 +365,7 @@ static std::string stringifySpvOptimizerMessage(spv_message_level_t level, const
}
void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
ShaderStage stage, ShaderModel shaderModel,
filament::backend::ShaderStage stage, filament::backend::ShaderModel shaderModel,
bool useFramebufferFetch, const DescriptorSets& descriptorSets,
const ShaderMinifier* minifier) {
using namespace msl;
@@ -650,7 +674,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
// SpvRules should be enough.
// I think this could cause the compilation to fail on gl_VertexID.
using Type = std::underlying_type_t<EShMessages>;
msg = EShMessages(Type(msg) | Type(EShMsgVulkanRules));
msg = EShMessages(Type(msg) | Type(EShMessages::EShMsgVulkanRules));
}
bool const ok = tShader.parse(&DefaultTBuiltInResource, internalConfig.langVersion, false, msg);
@@ -660,7 +684,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
}
// add texture lod bias
if (config.shaderType == ShaderStage::FRAGMENT &&
if (config.shaderType == backend::ShaderStage::FRAGMENT &&
config.domain == MaterialDomain::SURFACE) {
GLSLTools::textureLodBias(tShader);
}
@@ -736,8 +760,8 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
return true;
}
bool GLSLPostProcessor::preprocessOptimization(TShader& tShader,
Config const& config, InternalConfig& internalConfig) const {
bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
using TargetApi = MaterialBuilder::TargetApi;
assert_invariant(bool(internalConfig.spirvOutput) == (config.targetApi != TargetApi::OPENGL));
@@ -808,7 +832,7 @@ bool GLSLPostProcessor::preprocessOptimization(TShader& tShader,
}
bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
Config const& config, InternalConfig& internalConfig) const {
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
SpirvBlob spirv;
bool const optimizeForSize = mOptimization == MaterialBuilderBase::Optimization::SIZE;
@@ -904,7 +928,7 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
#else
try {
*internalConfig.glslOutput = glslCompiler.compile();
} catch (CompilerError e) {
} catch (spirv_cross::CompilerError e) {
slog.e << "ERROR: " << e.what() << io::endl;
return false;
}
@@ -924,8 +948,8 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
return true;
}
std::shared_ptr<Optimizer> GLSLPostProcessor::createEmptyOptimizer() {
auto optimizer = std::make_shared<Optimizer>(SPV_ENV_UNIVERSAL_1_3);
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createEmptyOptimizer() {
auto optimizer = std::make_shared<spvtools::Optimizer>(SPV_ENV_UNIVERSAL_1_3);
optimizer->SetMessageConsumer([](spv_message_level_t level,
const char* source, const spv_position_t& position, const char* message) {
if (!filterSpvOptimizerMessage(level)) {
@@ -937,7 +961,7 @@ std::shared_ptr<Optimizer> GLSLPostProcessor::createEmptyOptimizer() {
return optimizer;
}
std::shared_ptr<Optimizer> GLSLPostProcessor::createOptimizer(
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
MaterialBuilder::Optimization optimization, Config const& config) {
auto optimizer = createEmptyOptimizer();
@@ -971,11 +995,12 @@ void GLSLPostProcessor::optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv)
}
// Remove dead module-level objects: functions, types, vars
SpirvRemapWrapperRemap(spirv);
spv::spirvbin_t remapper(0);
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
}
void GLSLPostProcessor::fixupClipDistance(
SpirvBlob& spirv, Config const& config) const {
SpirvBlob& spirv, GLSLPostProcessor::Config const& config) const {
if (!config.usesClipDistance) {
return;
}
@@ -1015,7 +1040,7 @@ void GLSLPostProcessor::fixupClipDistance(
void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer, Config const& config) {
auto RegisterPass = [&](Optimizer::PassToken&& pass,
auto RegisterPass = [&](spvtools::Optimizer::PassToken&& pass,
MaterialBuilder::TargetApi apiFilter = MaterialBuilder::TargetApi::ALL) {
if (!(config.targetApi & apiFilter)) {
return;
@@ -1060,7 +1085,7 @@ void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer, Config c
}
void GLSLPostProcessor::registerSizePasses(Optimizer& optimizer, Config const& config) {
auto RegisterPass = [&](Optimizer::PassToken&& pass,
auto RegisterPass = [&](spvtools::Optimizer::PassToken&& pass,
MaterialBuilder::TargetApi apiFilter = MaterialBuilder::TargetApi::ALL) {
if (!(config.targetApi & apiFilter)) {
return;

View File

@@ -23,7 +23,6 @@
#include <private/filament/SamplerInterfaceBlock.h>
#include "ShaderMinifier.h"
#include "SpirvRemapWrapper.h"
#include <spirv-tools/optimizer.hpp>

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,8 @@
#include "MaterialVariants.h"
#include "shaders/ShaderGenerator.h"
#include <private/filament/EngineEnums.h>
#include <private/filament/Variant.h>
@@ -23,8 +25,16 @@
#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 {
std::vector<Variant> determineSurfaceVariants(
@@ -52,6 +62,58 @@ std::vector<Variant> determineSurfaceVariants(
if (fragmentVariant == 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;
}
@@ -71,7 +133,7 @@ std::vector<Variant> determinePostProcessVariants() {
std::vector<Variant> determineComputeVariants() {
// TODO: should we have variants for compute shaders?
std::vector<Variant> variants;
filament::Variant const variant(0);
filament::Variant variant(0);
variants.emplace_back(variant, filament::backend::ShaderStage::COMPUTE);
return variants;
}

View File

View File

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2017 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 "SpirvRemapWrapper.h"
#include <SPVRemapper.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <string>
namespace filamat {
void SpirvRemapWrapperSetUp() {
// SPIRV error handler registration should occur only once.
// Construct this SpirvRemapWrapper object only once.
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
utils::slog.e << str << utils::io::endl;
});
// Similar to above, we need to do a no-op remap to init a static
// table in the remapper before the jobs start using remap().
spv::spirvbin_t remapper(0);
// We need to provide at least a valid header to not crash.
std::vector<uint32_t> spirv {
0x07230203,// MAGIC
0, // VERSION
0, // GENERATOR
0, // BOUND
0 // SCHEMA, must be 0
};
remapper.remap(spirv, 0);
}
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv) {
// Remove dead module-level objects: functions, types, vars
spv::spirvbin_t remapper(0);
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
}
} // namespace filamat

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2017 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_SPIRVREMAPWRAPPER_H
#define TNT_SPIRVREMAPWRAPPER_H
#include <cstdint>
#include <vector>
namespace filamat {
void SpirvRemapWrapperSetUp();
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv);
} // namespace filamat
#endif //TNT_SPIRVREMAPWRAPPER_H

View File

@@ -39,7 +39,7 @@ namespace filamat {
MaterialUniformInterfaceBlockChunk::MaterialUniformInterfaceBlockChunk(
BufferInterfaceBlock const& uib) :
Chunk(MaterialUib),
Chunk(ChunkType::MaterialUib),
mUib(uib) {
}
@@ -60,7 +60,7 @@ void MaterialUniformInterfaceBlockChunk::flatten(Flattener& f) {
MaterialSamplerInterfaceBlockChunk::MaterialSamplerInterfaceBlockChunk(
SamplerInterfaceBlock const& sib) :
Chunk(MaterialSib),
Chunk(ChunkType::MaterialSib),
mSib(sib) {
}
@@ -81,7 +81,7 @@ void MaterialSamplerInterfaceBlockChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialSubpassInterfaceBlockChunk::MaterialSubpassInterfaceBlockChunk(SubpassInfo const& subpass) :
Chunk(MaterialSubpass),
Chunk(ChunkType::MaterialSubpass),
mSubpass(subpass) {
}
@@ -101,8 +101,8 @@ void MaterialSubpassInterfaceBlockChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialConstantParametersChunk::MaterialConstantParametersChunk(
FixedCapacityVector<MaterialConstant> constants)
: Chunk(MaterialConstants), mConstants(std::move(constants)) {}
utils::FixedCapacityVector<MaterialConstant> constants)
: Chunk(ChunkType::MaterialConstants), mConstants(std::move(constants)) {}
void MaterialConstantParametersChunk::flatten(Flattener& f) {
f.writeUint64(mConstants.size());
@@ -115,8 +115,8 @@ void MaterialConstantParametersChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialPushConstantParametersChunk::MaterialPushConstantParametersChunk(
CString const& structVarName, FixedCapacityVector<MaterialPushConstant> constants)
: Chunk(MaterialPushConstants),
CString const& structVarName, utils::FixedCapacityVector<MaterialPushConstant> constants)
: Chunk(ChunkType::MaterialPushConstants),
mStructVarName(structVarName),
mConstants(std::move(constants)) {}
@@ -133,7 +133,7 @@ void MaterialPushConstantParametersChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialBindingUniformInfoChunk::MaterialBindingUniformInfoChunk(Container list) noexcept
: Chunk(MaterialBindingUniformInfo),
: Chunk(ChunkType::MaterialBindingUniformInfo),
mBindingUniformInfo(std::move(list)) {
}
@@ -155,7 +155,7 @@ void MaterialBindingUniformInfoChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialAttributesInfoChunk::MaterialAttributesInfoChunk(Container list) noexcept
: Chunk(MaterialAttributeInfo),
: Chunk(ChunkType::MaterialAttributeInfo),
mAttributeInfo(std::move(list))
{
}
@@ -170,9 +170,11 @@ void MaterialAttributesInfoChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialDescriptorBindingsChuck::MaterialDescriptorBindingsChuck(Container const& sib) noexcept
: Chunk(MaterialDescriptorBindingsInfo),
mSamplerInterfaceBlock(sib) {
MaterialDescriptorBindingsChuck::MaterialDescriptorBindingsChuck(Container const& sib,
backend::DescriptorSetLayout const& perViewLayout) noexcept
: Chunk(ChunkType::MaterialDescriptorBindingsInfo),
mSamplerInterfaceBlock(sib),
mPerViewLayout(perViewLayout) {
}
void MaterialDescriptorBindingsChuck::flatten(Flattener& f) {
@@ -181,6 +183,13 @@ void MaterialDescriptorBindingsChuck::flatten(Flattener& f) {
using namespace backend;
// number of descriptor-sets
f.writeUint8(3);
// set
f.writeUint8(+DescriptorSetBindingPoints::PER_MATERIAL);
// samplers + 1 descriptor for the UBO
f.writeUint8(mSamplerInterfaceBlock.getSize() + 1);
@@ -201,13 +210,37 @@ void MaterialDescriptorBindingsChuck::flatten(Flattener& f) {
}
f.writeUint8(entry.binding);
}
// set
f.writeUint8(+DescriptorSetBindingPoints::PER_RENDERABLE);
f.writeUint8(descriptor_sets::getPerRenderableLayout().bindings.size());
for (auto const& entry: descriptor_sets::getPerRenderableLayout().bindings) {
auto const& name = descriptor_sets::getDescriptorName(
DescriptorSetBindingPoints::PER_RENDERABLE, entry.binding);
f.writeString({ name.data(), name.size() });
f.writeUint8(uint8_t(entry.type));
f.writeUint8(entry.binding);
}
// set
f.writeUint8(+DescriptorSetBindingPoints::PER_VIEW);
f.writeUint8(mPerViewLayout.bindings.size());
for (auto const& entry: mPerViewLayout.bindings) {
auto const& name = descriptor_sets::getDescriptorName(
DescriptorSetBindingPoints::PER_VIEW, entry.binding);
f.writeString({ name.data(), name.size() });
f.writeUint8(uint8_t(entry.type));
f.writeUint8(entry.binding);
}
}
// ------------------------------------------------------------------------------------------------
MaterialDescriptorSetLayoutChunk::MaterialDescriptorSetLayoutChunk(Container const& sib) noexcept
: Chunk(MaterialDescriptorSetLayoutInfo),
mSamplerInterfaceBlock(sib) {
MaterialDescriptorSetLayoutChunk::MaterialDescriptorSetLayoutChunk(Container const& sib,
backend::DescriptorSetLayout const& perViewLayout) noexcept
: Chunk(ChunkType::MaterialDescriptorSetLayoutInfo),
mSamplerInterfaceBlock(sib),
mPerViewLayout(perViewLayout) {
}
void MaterialDescriptorSetLayoutChunk::flatten(Flattener& f) {
@@ -233,11 +266,23 @@ void MaterialDescriptorSetLayoutChunk::flatten(Flattener& f) {
} else {
f.writeUint8(uint8_t(DescriptorType::SAMPLER));
}
f.writeUint8(uint8_t(entry.stages));
f.writeUint8(uint8_t(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT));
f.writeUint8(entry.binding);
f.writeUint8(uint8_t(DescriptorFlags::NONE));
f.writeUint16(0);
}
// samplers + 1 descriptor for the UBO
f.writeUint8(mPerViewLayout.bindings.size());
// all the material's sampler descriptors
for (auto const& entry: mPerViewLayout.bindings) {
f.writeUint8(uint8_t(entry.type));
f.writeUint8(uint8_t(entry.stageFlags));
f.writeUint8(entry.binding);
f.writeUint8(uint8_t(entry.flags));
f.writeUint16(entry.count);
}
}
} // namespace filamat

View File

@@ -19,12 +19,16 @@
#include "Chunk.h"
#include <private/filament/EngineEnums.h>
#include <backend/DriverEnums.h>
#include <backend/Program.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <tuple>
#include <utility>
#include <stdint.h>
@@ -41,10 +45,10 @@ namespace filamat {
class MaterialUniformInterfaceBlockChunk final : public Chunk {
public:
explicit MaterialUniformInterfaceBlockChunk(filament::BufferInterfaceBlock const& uib);
~MaterialUniformInterfaceBlockChunk() override = default;
~MaterialUniformInterfaceBlockChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
filament::BufferInterfaceBlock const& mUib;
};
@@ -54,10 +58,10 @@ private:
class MaterialSamplerInterfaceBlockChunk final : public Chunk {
public:
explicit MaterialSamplerInterfaceBlockChunk(filament::SamplerInterfaceBlock const& sib);
~MaterialSamplerInterfaceBlockChunk() override = default;
~MaterialSamplerInterfaceBlockChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
filament::SamplerInterfaceBlock const& mSib;
};
@@ -67,10 +71,10 @@ private:
class MaterialSubpassInterfaceBlockChunk final : public Chunk {
public:
explicit MaterialSubpassInterfaceBlockChunk(filament::SubpassInfo const& subpass);
~MaterialSubpassInterfaceBlockChunk() override = default;
~MaterialSubpassInterfaceBlockChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
filament::SubpassInfo const& mSubpass;
};
@@ -80,41 +84,41 @@ private:
class MaterialConstantParametersChunk final : public Chunk {
public:
explicit MaterialConstantParametersChunk(
FixedCapacityVector<filament::MaterialConstant> constants);
~MaterialConstantParametersChunk() override = default;
utils::FixedCapacityVector<filament::MaterialConstant> constants);
~MaterialConstantParametersChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
FixedCapacityVector<filament::MaterialConstant> mConstants;
utils::FixedCapacityVector<filament::MaterialConstant> mConstants;
};
// ------------------------------------------------------------------------------------------------
class MaterialPushConstantParametersChunk final : public Chunk {
public:
explicit MaterialPushConstantParametersChunk(CString const& structVarName,
FixedCapacityVector<filament::MaterialPushConstant> constants);
~MaterialPushConstantParametersChunk() override = default;
explicit MaterialPushConstantParametersChunk(utils::CString const& structVarName,
utils::FixedCapacityVector<filament::MaterialPushConstant> constants);
~MaterialPushConstantParametersChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
CString mStructVarName;
FixedCapacityVector<filament::MaterialPushConstant> mConstants;
utils::CString mStructVarName;
utils::FixedCapacityVector<filament::MaterialPushConstant> mConstants;
};
// ------------------------------------------------------------------------------------------------
class MaterialBindingUniformInfoChunk final : public Chunk {
using Container = FixedCapacityVector<std::tuple<
uint8_t, CString, filament::backend::Program::UniformInfo>>;
uint8_t, utils::CString, filament::backend::Program::UniformInfo>>;
public:
explicit MaterialBindingUniformInfoChunk(Container list) noexcept;
~MaterialBindingUniformInfoChunk() override = default;
~MaterialBindingUniformInfoChunk() final = default;
private:
void flatten(Flattener &) override;
void flatten(Flattener &) final;
Container mBindingUniformInfo;
};
@@ -122,13 +126,13 @@ private:
// ------------------------------------------------------------------------------------------------
class MaterialAttributesInfoChunk final : public Chunk {
using Container = FixedCapacityVector<std::pair<CString, uint8_t>>;
using Container = FixedCapacityVector<std::pair<utils::CString, uint8_t>>;
public:
explicit MaterialAttributesInfoChunk(Container list) noexcept;
~MaterialAttributesInfoChunk() override = default;
~MaterialAttributesInfoChunk() final = default;
private:
void flatten(Flattener &) override;
void flatten(Flattener &) final;
Container mAttributeInfo;
};
@@ -138,13 +142,15 @@ private:
class MaterialDescriptorBindingsChuck final : public Chunk {
using Container = filament::SamplerInterfaceBlock;
public:
explicit MaterialDescriptorBindingsChuck(Container const& sib) noexcept;
~MaterialDescriptorBindingsChuck() override = default;
explicit MaterialDescriptorBindingsChuck(Container const& sib,
filament::backend::DescriptorSetLayout const& perViewLayout) noexcept;
~MaterialDescriptorBindingsChuck() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
Container const& mSamplerInterfaceBlock;
filament::backend::DescriptorSetLayout mPerViewLayout;
};
// ------------------------------------------------------------------------------------------------
@@ -152,13 +158,15 @@ private:
class MaterialDescriptorSetLayoutChunk final : public Chunk {
using Container = filament::SamplerInterfaceBlock;
public:
explicit MaterialDescriptorSetLayoutChunk(Container const& sib) noexcept;
~MaterialDescriptorSetLayoutChunk() override = default;
explicit MaterialDescriptorSetLayoutChunk(Container const& sib,
filament::backend::DescriptorSetLayout const& perViewLayout) noexcept;
~MaterialDescriptorSetLayoutChunk() final = default;
private:
void flatten(Flattener&) override;
void flatten(Flattener&) final;
Container const& mSamplerInterfaceBlock;
filament::backend::DescriptorSetLayout mPerViewLayout;
};
} // namespace filamat

View File

@@ -604,13 +604,27 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
if (featureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
auto const perViewDescriptorSetLayout = getPerViewDescriptorSetLayoutWithVariant(
variant, variantFilter,
material.isLit || material.hasShadowMultiplier,
material.reflectionMode, material.refractionMode);
// this is the list of samplers we need to filter
auto const list = SamplerInterfaceBlock::filterSamplerList(
SibGenerator::getPerViewSib(variant).getSamplerInfoList(),
descriptor_sets::getPerViewDescriptorSetLayoutWithVariant(
variant, mMaterialDomain, variantFilter,
material.isLit || material.hasShadowMultiplier,
material.reflectionMode, material.refractionMode));
auto list = SibGenerator::getPerViewSib(variant).getSamplerInfoList();
// remove all the samplers that are not included in the descriptor-set layout
list.erase(
std::remove_if(list.begin(), list.end(),
[&perViewDescriptorSetLayout](auto const& entry) {
auto pos = std::find_if(
perViewDescriptorSetLayout.bindings.begin(),
perViewDescriptorSetLayout.bindings.end(),
[&entry](const auto& item) {
return item.binding == entry.binding;
});
return pos == perViewDescriptorSetLayout.bindings.end();
}), list.end());
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_VIEW, list);
}
@@ -827,4 +841,22 @@ 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

Some files were not shown because too many files have changed in this diff Show More