Compare commits

..
Author SHA1 Message Date
Eliza Velasquez 84cecd334b materials: fix mutable spec constants nvidia bug
It turns out that I didn't understand how `FixedCapacityVector` works.
2025-09-03 18:13:09 -07:00
Eliza Velasquez bb6ebd3aea materials: reintroduce mutable spec constants
This change apparently breaks nvidia, still working on it.
2025-08-27 13:27:39 -07:00
188 changed files with 11661 additions and 3163 deletions
+1 -10
View File
@@ -532,15 +532,6 @@ if (FILAMENT_SUPPORTS_OPENGL)
add_definitions(-DFILAMENT_SUPPORTS_OPENGL)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
option(FILAMENT_ENABLE_PERFETTO "Enable perfetto SDK on Android" OFF)
else()
option(FILAMENT_ENABLE_PERFETTO "Enable perfetto SDK on Android" ON)
endif()
if (FILAMENT_ENABLE_PERFETTO)
add_definitions(-DFILAMENT_ENABLE_PERFETTO)
endif()
# By default, build with Vulkan support on desktop platforms, although clients must request to use
# it at run time.
if (WIN32 OR WEBGL OR IOS)
@@ -642,7 +633,7 @@ endif()
# With WebGPU, Tint does not support ClipDistance which is used in Stereo. Mentioned in comment
# https://github.com/google/dawn/blob/855d17b08abdf02f9142bf5a8f14d0ea088810a4/src/tint/lang/spirv/reader/ast_parser/function.cc#L4434
if (FILAMENT_SUPPORTS_WEBGPU)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=stereo)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=skinning,stereo)
endif()
# Disable ESSL 1.0 code generation.
+3
View File
@@ -7,3 +7,6 @@ We are chaning the way Vulkan buffers are handled. We need to switch over to a m
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
- materials: new mutable specialization constants feature. See the [materials documentation](https://google.github.io/filament/Materials.html) for details. [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.65.1'
implementation 'com.google.android.filament:filament-android:1.64.0'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.65.1'
pod 'Filament', '~> 1.64.0'
```
## Documentation
-12
View File
@@ -7,18 +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.65.1
- `setFrameScheduledCallback` now works on all backends (frame presentation scheduling is still only
available on Metal). Non-Metal backends can use the callback to be notified when Filament has
finished processing a frame on the CPU.
- materials: added `getEyeFromViewMatrix()` for vertex shader [⚠️ **Recompile Materials**]
- matc: make `--workarounds=none` the default [**Recompile Materials to take effect**]
## v1.65.0
lighting: the intermediate froxel record buffer is now dynamically sized [⚠️ **New Material Version**]
## v1.64.1
- Update CMake minimum version to 3.22.1
@@ -146,7 +146,7 @@ abstract class MaterialCompiler extends TaskWithBinary {
.gradleProperty("com.google.android.filament.include-webgpu")
.forUseAtConfigurationTime().present
if (include_webgpu) {
matcArgs += ['-a', 'webgpu', '--variant-filter=stereo']
matcArgs += ['-a', 'webgpu', '--variant-filter=skinning,stereo']
}
def mat_no_opt = providers
-2
View File
@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.19)
project(filamat-android)
set(CMAKE_CXX_STANDARD 20)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
+17 -19
View File
@@ -7,8 +7,6 @@ option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
add_library(filament STATIC IMPORTED)
@@ -132,14 +130,6 @@ add_library(filament-jni SHARED
../common/NioUtils.cpp
)
target_include_directories(filament-jni PRIVATE
..
${FILAMENT_DIR}/include
../../filament/backend/include
../../third_party/robin-map
../../third_party/perfetto
../../libs/utils/include)
# Ordering is significant in the following list. The PRIVATE qualifier prevents transitive deps.
target_link_libraries(filament-jni
PRIVATE filament-generatePrefilterMipmap
@@ -154,21 +144,29 @@ target_link_libraries(filament-jni
PRIVATE android
PRIVATE jnigraphics
PRIVATE utils
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE abseil # needed only when FILAMENT_USE_ABSEIL_LOGGING is defined
PRIVATE perfetto
PRIVATE abseil
PRIVATE zstd
# libgeometry is PUBLIC because gltfio uses it.
PUBLIC geometry
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:vkshaders>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:smol-v>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn>
$<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:vkshaders>
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:smol-v>
)
target_include_directories(filament-jni PRIVATE
..
${FILAMENT_DIR}/include
../../filament/backend/include
../../third_party/robin-map
../../third_party/perfetto
../../libs/utils/include)
# Force a relink when the version script is changed:
set_target_properties(filament-jni PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT})
@@ -60,6 +60,14 @@ static void setParameter(JNIEnv* env, jlong nativeMaterialInstance, jstring name
env->ReleaseStringUTFChars(name_, name);
}
template<typename T>
static void setConstant(JNIEnv* env, jlong nativeMaterialInstance, jstring name_, T v) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
const char *name = env->GetStringUTFChars(name_, 0);
instance->setConstant(name, v);
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetParameterBool(JNIEnv *env, jclass,
@@ -264,6 +272,13 @@ Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
jlong nativeMaterialInstance, jstring name_, jboolean x) {
setConstant(env, nativeMaterialInstance, name_, bool(x));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetScissor(
@@ -450,13 +450,6 @@ Java_com_google_android_filament_RenderableManager_nGetPrimitiveCount(JNIEnv*, j
return (jint) rm->getPrimitiveCount((RenderableManager::Instance) i);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_RenderableManager_nGetInstanceCount(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i) {
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
return (jint) rm->getInstanceCount((RenderableManager::Instance) i);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nSetMaterialInstanceAt(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i, jint primitiveIndex, jlong nativeMaterialInstance) {
@@ -402,6 +402,16 @@ public class MaterialInstance {
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
}
/**
* Sets the value of a bool constant.
*
* @param name the name of the material constant
* @param x the value of the material constant
*/
public void setConstant(@NonNull String name, boolean x) {
nSetConstantBool(getNativeObject(), name, x);
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
@@ -921,6 +931,9 @@ public class MaterialInstance {
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
private static native void nSetConstantBool(long nativeMaterialInstance,
@NonNull String name, boolean x);
private static native void nSetParameterTexture(long nativeMaterialInstance,
@NonNull String name, long nativeTexture, long sampler);
@@ -851,14 +851,6 @@ public class RenderableManager {
return nGetPrimitiveCount(mNativeObject, i);
}
/**
* Gets the immutable number of instances in the given renderable.
*/
@IntRange(from = 0)
public int getInstanceCount(@EntityInstance int i) {
return nGetInstanceCount(mNativeObject, i);
}
/**
* Changes the material instance binding for the given primitive.
*
@@ -1026,7 +1018,6 @@ public class RenderableManager {
private static native boolean nIsShadowReceiver(long nativeRenderableManager, int i);
private static native void nGetAxisAlignedBoundingBox(long nativeRenderableManager, int i, float[] center, float[] halfExtent);
private static native int nGetPrimitiveCount(long nativeRenderableManager, int i);
private static native int nGetInstanceCount(long nativeRenderableManager, int i);
private static native void nSetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex, long nativeMaterialInstance);
private static native void nClearMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
private static native long nGetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
@@ -231,7 +231,7 @@ public class View {
*
* <p>
* The View does not take ownership of the Scene pointer. Before destroying a Camera, be sure
* to remove it from all associated Views. If the camera isn't set, Renderer::render() will result in a no-op.
* to remove it from all assoicated Views.
* </p>
*
* @see #getCamera
+11 -31
View File
@@ -1,14 +1,6 @@
cmake_minimum_required(VERSION 3.19)
project(filament-utils-android)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
set(IMAGEIO_DIR ../../libs/imageio)
@@ -38,16 +30,7 @@ add_library(iblprefilter STATIC IMPORTED)
set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
add_library(perfetto STATIC IMPORTED)
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
add_library(filament-utils-jni SHARED
@@ -70,25 +53,22 @@ add_library(filament-utils-jni SHARED
target_compile_definitions(filament-utils-jni PUBLIC IMAGEIO_LITE=1)
target_include_directories(filament-utils-jni PRIVATE
..
${FILAMENT_DIR}/include
..
../../filament/backend/include
${IMAGEIO_DIR}/include
../../libs/utils/include)
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT})
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.symbols)
# The ordering in the following list is important because CMake does not have dependency information.
target_link_libraries(filament-utils-jni
PRIVATE gltfio-jni
PRIVATE civetweb
PRIVATE camutils
PRIVATE iblprefilter
PRIVATE image
PRIVATE filament-jni
PRIVATE ktxreader
PRIVATE viewer
PRIVATE log
PRIVATE utils
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
gltfio-jni
civetweb
camutils
iblprefilter
image
ktxreader
viewer
)
+69 -37
View File
@@ -1,27 +1,20 @@
cmake_minimum_required(VERSION 3.19)
project(gltfio-android)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
set(GLTFIO_DIR ../../libs/gltfio)
set(DRACO_DIR ../../third_party/draco)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../filament-android ${CMAKE_CURRENT_BINARY_DIR}/filament-android)
add_library(gltfio_core STATIC IMPORTED)
set_target_properties(gltfio_core PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_core.a)
add_library(dracodec STATIC IMPORTED)
set_target_properties(dracodec PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libdracodec.a)
add_library(meshoptimizer STATIC IMPORTED)
set_target_properties(meshoptimizer PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libmeshoptimizer.a)
add_library(ktxreader STATIC IMPORTED)
set_target_properties(ktxreader PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libktxreader.a)
@@ -34,6 +27,10 @@ add_library(basis_transcoder STATIC IMPORTED)
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
add_library(zstd STATIC IMPORTED)
set_target_properties(zstd PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libzstd.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
@@ -50,11 +47,60 @@ add_library(uberarchive STATIC IMPORTED)
set_target_properties(uberarchive PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberarchive.a)
set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
set(GLTFIO_SRCS
${GLTFIO_DIR}/include/gltfio/Animator.h
${GLTFIO_DIR}/include/gltfio/AssetLoader.h
${GLTFIO_DIR}/include/gltfio/FilamentAsset.h
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
${GLTFIO_DIR}/include/gltfio/NodeManager.h
${GLTFIO_DIR}/include/gltfio/TrsTransformManager.h
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
${GLTFIO_DIR}/include/gltfio/math.h
${GLTFIO_DIR}/src/ArchiveCache.cpp
${GLTFIO_DIR}/src/ArchiveCache.h
${GLTFIO_DIR}/src/Animator.cpp
${GLTFIO_DIR}/src/AssetLoader.cpp
${GLTFIO_DIR}/src/DependencyGraph.cpp
${GLTFIO_DIR}/src/DependencyGraph.h
${GLTFIO_DIR}/src/DracoCache.cpp
${GLTFIO_DIR}/src/DracoCache.h
${GLTFIO_DIR}/src/FFilamentAsset.h
${GLTFIO_DIR}/src/FFilamentInstance.h
${GLTFIO_DIR}/src/FilamentAsset.cpp
${GLTFIO_DIR}/src/FilamentInstance.cpp
${GLTFIO_DIR}/src/FNodeManager.h
${GLTFIO_DIR}/src/FTrsTransformManager.h
${GLTFIO_DIR}/src/GltfEnums.h
${GLTFIO_DIR}/src/Ktx2Provider.cpp
${GLTFIO_DIR}/src/MaterialProvider.cpp
${GLTFIO_DIR}/src/NodeManager.cpp
${GLTFIO_DIR}/src/TrsTransformManager.cpp
${GLTFIO_DIR}/src/ResourceLoader.cpp
${GLTFIO_DIR}/src/StbProvider.cpp
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/TangentsJob.h
${GLTFIO_DIR}/src/UbershaderProvider.cpp
${GLTFIO_DIR}/src/Utility.cpp
${GLTFIO_DIR}/src/Utility.h
${GLTFIO_DIR}/src/Wireframe.cpp
${GLTFIO_DIR}/src/Wireframe.h
${GLTFIO_DIR}/src/downcast.h
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.cpp
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.h
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.cpp
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.h
${GLTFIO_DIR}/src/extended/TangentsJobExtended.cpp
${GLTFIO_DIR}/src/extended/TangentsJobExtended.h
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.cpp
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.h
src/main/cpp/Animator.cpp
src/main/cpp/AssetLoader.cpp
src/main/cpp/FilamentAsset.cpp
@@ -72,38 +118,24 @@ set(GLTFIO_SRCS
set(GLTFIO_INCLUDE_DIRS
..
${FILAMENT_DIR}/include
${FILAMENT_DIR}/backend/include
../../filament/backend/include
../../libs/gltfio/include
../../third_party/zstd/lib
../../third_party/cgltf
../../third_party/meshoptimizer/src
../../third_party/robin-map
../../third_party/stb
../../third_party/perfetto
../../libs/utils/include
../../libs/ktxreader/include
)
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
target_link_libraries(gltfio-jni filament-jni utils perfetto uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
target_link_libraries(gltfio-jni dracodec meshoptimizer)
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/tnt)
# Force a relink when the version script is changed:
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols;${VERSION_SCRIPT}")
# The ordering in the following list is important because CMake does not have dependency information.
target_link_libraries(gltfio-jni
PRIVATE gltfio_core
PRIVATE ktxreader
PUBLIC filament-jni
PRIVATE stb
PRIVATE basis_transcoder
PRIVATE uberarchive
PRIVATE dracodec
PRIVATE utils
PRIVATE uberzlib
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE log # needed only when perfetto above is used
)
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.65.1
VERSION_NAME=1.64.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -8
View File
@@ -75,8 +75,6 @@ function print_help {
echo " -S type"
echo " Enable stereoscopic rendering where type is one of [instanced|multiview]. This is only"
echo " meant for building the samples."
echo " -P"
echo " Enable perfetto traces on Android. Disabled by default on the Release build, enabled otherwise."
echo ""
echo "Build types:"
echo " release"
@@ -206,7 +204,6 @@ MATOPT_GRADLE_OPTION=""
ASAN_UBSAN_OPTION=""
COVERAGE_OPTION=""
ENABLE_PERFETTO=""
BACKEND_DEBUG_FLAG_OPTION=""
@@ -416,7 +413,6 @@ function build_android_target {
${WEBGPU_OPTION} \
${BACKEND_DEBUG_FLAG_OPTION} \
${STEREOSCOPIC_OPTION} \
${ENABLE_PERFETTO} \
../..
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
../../compile_commands.json
@@ -810,7 +806,7 @@ function check_debug_release_build {
pushd "$(dirname "$0")" > /dev/null
while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:P" opt; do
while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:" opt; do
case ${opt} in
h)
print_help
@@ -958,9 +954,6 @@ while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:P" opt; do
V) COVERAGE_OPTION="-DFILAMENT_ENABLE_COVERAGE=ON"
echo "Enabled coverage"
;;
P) ENABLE_PERFETTO="-DFILAMENT_ENABLE_PERFETTO=ON"
echo "Enabled perfetto"
;;
x) BACKEND_DEBUG_FLAG_OPTION="-DFILAMENT_BACKEND_DEBUG_FLAG=${OPTARG}"
;;
S) case $(echo "${OPTARG}" | tr '[:upper:]' '[:lower:]') in
+22 -25
View File
@@ -212,7 +212,7 @@ when using textures.
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by `baseColor`).
(reflected light takes on the color of the surfaced as defined by `baseColor`).
The effect of `metallic` is shown in figure [metallicProperty] (click on the image to see a
larger version).
@@ -248,7 +248,7 @@ The effect of `roughness` on metallic surfaces is shown in figure [roughnessCond
When refraction through an object is enabled (using a `refractonType` of `thin` or `solid`), the
`roughness` property will also affect the refractions, as shown in figure
[roughnessRefractionProperty] (click on the image to see a larger version).
![Figure [roughnessRefractionProperty]: Refractive sphere with `roughness` varying from 0.0
(left) to 1.0 (right)](images/materials/refraction_roughness.png)
@@ -307,7 +307,7 @@ The sheen color controls the color appearance and strength of an optional sheen
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section [Cloth model] for more information about cloth and fabric materials.
The effect of `sheenColor` is shown in figure [materialSheenColor]
@@ -520,14 +520,14 @@ light to bend further away from the initial path.
Table [commonMatIOR] describes acceptable refractive indices for various types of materials.
Material | IOR
Material | IOR
--------------------------:|:-----------------
Air | 1.0
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
[Table [commonMatIOR]: Index of refraction of common materials]
The appearance of a refractive material will greatly depend on the `refractionType` and
@@ -995,10 +995,10 @@ Value
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
mobile), `low`, `medium`, `high`. The type must be one of the types described in
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
Type | Description
:----------------------|:---------------------------------
@@ -2476,17 +2476,14 @@ type aliases:
### Matrices
Name | Type | Description
:-----------------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getEyeFromViewMatrix()** | float4x4 | Matrix that converts from view space to eye space
**getEyeFromViewMatrix(int eyeIndex)** | float4x4 | Matrix that converts from view space to eye space for the eye referred to by eyeIndex
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getClipFromWorldMatrix(int eyeIndex)** | float4x4 | Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
### Frame constants
@@ -2642,7 +2639,7 @@ standard skybox material. It produces a list of 2 parameters, named `showSun` an
respectively a boolean and a cubemap texture.
```text
$ matc --reflect parameters filament/src/materials/skybox.mat
$ matc --reflect parameters filament/src/materials/skybox.mat
{
"parameters": [
{
@@ -2658,7 +2655,7 @@ $ matc --reflect parameters filament/src/materials/skybox.mat
}
]
}
```
```
### --variant-filter
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.64.1'
implementation 'com.google.android.filament:filament-android:1.64.0'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.64.1'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.64.0'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+1 -1
View File
@@ -162,7 +162,7 @@
<p>This tool makes it easy to analyze the composition of Android applications that use Filament.</p>
<ul>
<li>Filament materials are shown in the treemap if <code>resgen --json</code> was used in the build.</li>
<li>The input path can be a <code>.so</code> or <code>.a</code> file, a folder, or a zip archive (apk or aar).</li>
<li>The input path can be a so file, folder, or zip archive (apk or aar).</li>
<li>If the path is a zip or folder, interactively finds the file to analyze.</li>
<li>The generated web report is a self-contained HTML file.</li>
<li>Reports the gzipped size of all Filament materials.</li>
+4 -4
View File
@@ -178,9 +178,9 @@ content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5)
counter-increment: h6;margin-right:10px}
</style><style>.hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:#000;-webkit-text-size-adjust:none}.hljs-comment{color:#006a00}.hljs-keyword{color:#02E}.hljs-literal,.nginx .hljs-title{color:#aa0d91}.method,.hljs-list .hljs-title,.hljs-tag .hljs-title,.setting .hljs-value,.hljs-winutils,.tex .hljs-command,.http .hljs-title,.hljs-request,.hljs-status,.hljs-name{color:#008}.hljs-envvar,.tex .hljs-special{color:#660}.hljs-string{color:#c41a16}.hljs-tag .hljs-value,.hljs-cdata,.hljs-filter .hljs-argument,.hljs-attr_selector,.apache .hljs-cbracket,.hljs-date,.hljs-regexp{color:#080}.hljs-sub .hljs-identifier,.hljs-pi,.hljs-tag,.hljs-tag .hljs-keyword,.hljs-decorator,.ini .hljs-title,.hljs-shebang,.hljs-prompt,.hljs-hexcolor,.hljs-rule .hljs-value,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-number,.css .hljs-function,.hljs-function .hljs-title,.coffeescript .hljs-attribute{color:#A0C}.hljs-function .hljs-title{font-weight:bold;color:#000}.hljs-class .hljs-title,.smalltalk .hljs-class,.hljs-type,.hljs-typename,.hljs-tag .hljs-attribute,.hljs-doctype,.hljs-class .hljs-id,.hljs-built_in,.setting,.hljs-params,.clojure .hljs-attribute{color:#5c2699}.hljs-variable{color:#3f6e74}.css .hljs-tag,.hljs-rule .hljs-property,.hljs-pseudo,.hljs-subst{color:#000}.css .hljs-class,.css .hljs-id{color:#9b703f}.hljs-value .hljs-important{color:#ff7700;font-weight:bold}.hljs-rule .hljs-keyword{color:#c5af75}.hljs-annotation,.apache .hljs-sqbracket,.nginx .hljs-built_in{color:#9b859d}.hljs-preprocessor,.hljs-preprocessor *,.hljs-pragma{color:#643820}.tex .hljs-formula{background-color:#eee;font-style:italic}.diff .hljs-header,.hljs-chunk{color:#808080;font-weight:bold}.diff .hljs-change{background-color:#bccff9}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-comment .hljs-doctag{font-weight:bold}.method .hljs-id{color:#000}</style><style>div.title { padding-top: 40px; } div.afterTitles { height: 15px; }</style><meta charset="utf-8"></p>
<style>img { max-width: 100%; }</style>
<p><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{,\mathrm{#1}}$$
<script type="text/x-mathjax-config">MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "AMS"} } });</script><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{\,\mathrm{#1}}$$
</span>
<span class="md"><p><title>Physically Based Rendering in Filament</title><div class="title"> Physically Based Rendering in Filament </div></p>
<span class="md"><p><title>Physically Based Rendering in Filament</title><div class="title"> Physically Based Rendering in Filament </div>
<div class="afterTitles"></div>
</p><p>
</p>
@@ -2060,7 +2060,7 @@ In practice only 4 or 9 coefficients (i.e.: 2 or 3 bands) are enough for \(\cosT
In practice we pre-convolve \(\Lt\) with \(\cosTheta\) and pre-scale these coefficients by the basis scaling factors \(K_l^m\) so that the reconstruction code is as simple as possible in the shader:
</p><a class="target" name="listing_irradiancesh">&nbsp;</a><pre class="listing tilde"><code><span class="line"></span>vec3 irradianceSH(vec3 n) {
<span class="line"></span> // uniform vec3 sphericalHarmonics<span class="hljs-selector-attr">[9]</span>
<span class="line"></span> // We can <span class="hljs-selector-tag">use</span> only the first <span class="hljs-number">2</span> bands for better performance
<span class="line"></span> // We can use only the first <span class="hljs-number">2</span> bands for better performance
<span class="line"></span> return
<span class="line"></span> sphericalHarmonics<span class="hljs-selector-attr">[0]</span>
<span class="line"></span> + sphericalHarmonics<span class="hljs-selector-attr">[1]</span> * (n<span class="hljs-selector-class">.y</span>)
@@ -4395,7 +4395,7 @@ For Fast Realistic Image Display. <em class="asterisk">SIGGRAPH '00 Proceedings
</div><div class="bib">[<a class="target" name="citation-schlick94">&nbsp;</a><b>Schlick94</b>] Christophe Schlick. 1994. An Inexpensive BRDF Model for Physically-Based Rendering. <em class="asterisk">Computer Graphics Forum</em>, 13 (3), 233–246.
</div><div class="bib">[<a class="target" name="citation-walter07">&nbsp;</a><b>Walter07</b>] Bruce Walter et al. 2007. Microfacet Models for Refraction through Rough Surfaces. <em class="asterisk">Proceedings of the Eurographics Symposium on Rendering</em>.
</div>
</sample></float></sample></float></float></p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
</sample></float></sample></float></float></p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
+9 -12
View File
@@ -178,9 +178,9 @@ content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5)
counter-increment: h6;margin-right:10px}
</style><style>.hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:#000;-webkit-text-size-adjust:none}.hljs-comment{color:#006a00}.hljs-keyword{color:#02E}.hljs-literal,.nginx .hljs-title{color:#aa0d91}.method,.hljs-list .hljs-title,.hljs-tag .hljs-title,.setting .hljs-value,.hljs-winutils,.tex .hljs-command,.http .hljs-title,.hljs-request,.hljs-status,.hljs-name{color:#008}.hljs-envvar,.tex .hljs-special{color:#660}.hljs-string{color:#c41a16}.hljs-tag .hljs-value,.hljs-cdata,.hljs-filter .hljs-argument,.hljs-attr_selector,.apache .hljs-cbracket,.hljs-date,.hljs-regexp{color:#080}.hljs-sub .hljs-identifier,.hljs-pi,.hljs-tag,.hljs-tag .hljs-keyword,.hljs-decorator,.ini .hljs-title,.hljs-shebang,.hljs-prompt,.hljs-hexcolor,.hljs-rule .hljs-value,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-number,.css .hljs-function,.hljs-function .hljs-title,.coffeescript .hljs-attribute{color:#A0C}.hljs-function .hljs-title{font-weight:bold;color:#000}.hljs-class .hljs-title,.smalltalk .hljs-class,.hljs-type,.hljs-typename,.hljs-tag .hljs-attribute,.hljs-doctype,.hljs-class .hljs-id,.hljs-built_in,.setting,.hljs-params,.clojure .hljs-attribute{color:#5c2699}.hljs-variable{color:#3f6e74}.css .hljs-tag,.hljs-rule .hljs-property,.hljs-pseudo,.hljs-subst{color:#000}.css .hljs-class,.css .hljs-id{color:#9b703f}.hljs-value .hljs-important{color:#ff7700;font-weight:bold}.hljs-rule .hljs-keyword{color:#c5af75}.hljs-annotation,.apache .hljs-sqbracket,.nginx .hljs-built_in{color:#9b859d}.hljs-preprocessor,.hljs-preprocessor *,.hljs-pragma{color:#643820}.tex .hljs-formula{background-color:#eee;font-style:italic}.diff .hljs-header,.hljs-chunk{color:#808080;font-weight:bold}.diff .hljs-change{background-color:#bccff9}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-comment .hljs-doctag{font-weight:bold}.method .hljs-id{color:#000}</style><style>div.title { padding-top: 40px; } div.afterTitles { height: 15px; }</style><meta charset="utf-8"></p>
<style>img { max-width: 100%; }</style>
<p><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{,\mathrm{#1}}$$
<script type="text/x-mathjax-config">MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "AMS"} } });</script><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{\,\mathrm{#1}}$$
</span>
<span class="md"><p><title>Filament Materials Guide</title><div class="title"> Filament Materials Guide </div></p>
<span class="md"><p><title>Filament Materials Guide</title><div class="title"> Filament Materials Guide </div>
<div class="afterTitles"></div>
</p><p>
</p>
@@ -504,7 +504,7 @@ when using textures.</p>
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by <code>baseColor</code>).
(reflected light takes on the color of the surfaced as defined by <code>baseColor</code>).
</p><p>
The effect of <code>metallic</code> is shown in <a href="#figure_metallicproperty" target="_self">figure&nbsp;1</a> (click on the image to see a
larger version).
@@ -597,7 +597,7 @@ indices.
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.</p>
</p><p>
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section <a href="#toc3.3" target="_self">3.3</a> for more information about cloth and fabric materials.
</p><p>
The effect of <code>sheenColor</code> is shown in <a href="#figure_materialsheencolor" target="_self">figure&nbsp;7</a>
@@ -1220,10 +1220,10 @@ non-shader data.</p>
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
</p></dd></dl><div class='table'>
<a class="target" name="table_materialparamstypes">&nbsp;</a><table class="table longtable"><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
<tr><td style="text-align:left"> bool </td><td style="text-align:left"> Single boolean </td></tr>
@@ -2361,10 +2361,7 @@ type aliases:</p>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view/eye space to world space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view/eye space to clip (NDC) space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getViewFromClipMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from clip (NDC) space to view/eye space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getEyeFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view space to eye space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getEyeFromViewMatrix(int eyeIndex)</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view space to eye space for the eye referred to by eyeIndex </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromWorldMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from world to clip (NDC) space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromWorldMatrix(int eyeIndex)</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldFromClipMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from clip (NDC) space to world space </td></tr>
</table></div>
</p>
@@ -2504,7 +2501,7 @@ a good compromise between runtime performance and size.</p>
metadata in JSON format. The example below prints out the list of parameters defined in Filament's
standard skybox material. It produces a list of 2 parameters, named <code>showSun</code> and <code>skybox</code>,
respectively a boolean and a cubemap texture.</p>
</p><pre class="listing backtick"><code><span class="line"></span>$ matc --reflect parameters filament/src/materials/skybox.mat
</p><pre class="listing backtick"><code><span class="line"></span>$ matc --reflect parameters filament/src/materials/skybox.mat
<span class="line"></span>{
<span class="line"></span> &quot;parameters&quot;: [
<span class="line"></span> {
@@ -2603,7 +2600,7 @@ Finally if <code>variantFilter</code> contains the <code>fog</code> filter, an e
</p><p>
Be aware that <code>external</code> samplers account for 2 regular samplers.</div>
</p><p>
</p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
</p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
+2 -2
View File
@@ -250,7 +250,7 @@ execution profile data.</p>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/framegraph.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -264,7 +264,7 @@ execution profile data.</p>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/framegraph.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -331,7 +331,7 @@ nodes</li>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/performance_analysis.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/coverage.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -345,7 +345,7 @@ nodes</li>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/performance_analysis.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/coverage.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
-352
View File
@@ -1,352 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Performance analysis - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="performance-analysis"><a class="header" href="#performance-analysis">Performance Analysis</a></h1>
<h2 id="android"><a class="header" href="#android">Android</a></h2>
<h3 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h3>
<ul>
<li>Download and install Android GPU Inspector (AGI). See https://developer.android.com/agi.</li>
</ul>
<hr />
<h4 id="profiling"><a class="header" href="#profiling">Profiling</a></h4>
<ol>
<li>
<p>Before profiling the application or analyzing the performance in a consistent way, ideally
the <strong>GPU frequency on the target hardware should get locked</strong>. In order to do this, you need to do the following:</p>
<ol>
<li>Ensure your device is OEM unlocked. If your phone is carrier-locked, you may need
to wait a period, such as 60 or 90 days after activation to be eligible for unlocking.
Some phones don't support this at all. You will need to enable developer options
(e.g. Settings &gt; About Phone and tap the Build number 7 times). You need to go to
Settings &gt; System &gt; Developer options and toggle on "OEM unlocking".</li>
<li>Next, you need to unlock the phone. You will need to install Android SDK Platform
Tools on you computer, enable "USB debugging" in your phone's Settings &gt; System &gt; Developer options.</li>
<li>Connect the phone to the computer via a USB cable and run from the command line:
<pre><code class="language-shell">adb reboot bootloader
# once the phone is in bootloader mode, run the following to begin the unlocking
# process:
fastboot flashing unlock
</code></pre>
A warning will appear on your phone's screen. Use the volume buttons to navigate and
the power button to select the "Unlock the bootloader" option. The phone will perform
a factory data reset and reboot with an unlocked bootloader.</li>
<li>You would need to flash an image to the phone with root permissions, such as a *-userdebug or *-eng
build. One way to do this is with the <a href="https://flash.android.com/">Android Flash Tool</a>. Connect the
tool to your device and find a build to flash ending in <code>-userdebug</code> or <code>-eng</code>. Once you have that
selected run <code>Install build</code>.</li>
<li>Shell into your device as root and configure the gpu frequency to be locked, e.g.:
<pre><code class="language-shell">adb shell
su
# navigate to the system GPU directory. this varies on different phones. One phone might have
# it at /sys/class/kgsl/kgsl-3d0 and another might be in something similar, maybe with "mali" instead
# of "kgsl". At the time of writing this for the device at hand it was /sys/devices/platform/1f000000.mali
cd /sys/devices/platform/1f000000.mali
# get the current available GPU governors and frequencies.
# note that some systems may have these at gpu_available_governors and gpu_available_frequencies, but
# the system at the time of writing this had available_governors and available_frequences
cat available_governors
cat available_frequencies
# depending on the governors, you may want to set it prioritize performance over other things like
# battery. Some systems allow you to do this with something like (although, for the device used at the
# time of writing this did not have an equivalent option):
echo performance &gt; gpu_governor
# finally, lock your frequency in, usually to something high like 897 MHz. Some systems may have you
# pipe the value to gpu_min_freq and gpu_max_freq, but the system used at the time of writing this had:
echo 940000 &gt; hint_min_freq
echo 940000 &gt; hint_max_freq
# you can typically verify the GPU is running at that frequency consistently by running something like
# the following a few times over time, which should show the frequency you want to lock the device to:
cat cur_freq
</code></pre>
</li>
<li>You may need to re-apply the <code>hint_min_freq</code> just before starting the profiling trace and check before and after
that the frequency remained at the value expected. Some systems may adjust the frequency on you, but you
may want to ensure the frequency remains the same through the analysis.</li>
<li>The GPU frequency settings should be undone after restarting the device, but after you have done your app profiling,
you can revert the state of the device, such as the OS build image, back to the way you had it
initially, as needed.</li>
</ol>
</li>
<li>
<p>Build a release build of Filament with the applicable backend(s) enabled
<em>(+ any special flags for enabling sys strace. Nothing special is needed for Vulkan or WebGPU aside from
building a release build with no flags)</em> <em>(debug builds for this are useless)</em></p>
<pre><code class="language-shell"># the following command assumes you are in the root filament directory
# and ANDROID_HOME is exported (and possibly also CC and CXX on linux as needed)
#
# NOTE: to build with WebGPU support you need to explicitly include the -W flag
# (it doesn't get compiled in by default), e.g.:
# ./build.sh -W -p android,desktop -i release
#
# Note that you can speed this up a bit (and reduce disk space usage) by limiting the target to just
# the ABI you plan on testing with the -q flag, e.g. -q arm64-v8a. If you do this, you
# will need to update the android/gradle.properties file to specify the ABI(s) you are targeting
# with the com.google.android.filament.abis property.
# Thus, a build command that would target BOTH Vulkan AND WebGPU AND only target the ARM64 ABI would look something
# like:
# ./build.sh -W -q arm64-v8a -p android,desktop -i release
./build.sh -p android,desktop -i release
</code></pre>
</li>
<li>
<p>Connect your Android device to your computer via a USB cord with USB debugging enabled and configure
the system property to default to the desired backend, e.g.
<em>(to determine how these numbers map to the backends, see the <code>enum class Backend</code>
definition in <a href="../../../../filament/backend/include/backend/DriverEnums.h">filament/filament/backend/include/backend/DriverEnums.h</a>)</em>:</p>
<pre><code class="language-shell"># to set the backend to Vulkan:
adb shell setprop debug.filament.backend 2
# to set the backend to WebGPU:
adb shell setprop debug.filament.backend 4
# to view the current property:
adb shell getprop debug.filament.backend
</code></pre>
</li>
<li>
<p>Build and run a sample, e.g. sample-gltf-viewer, on your Android device
<em>(<a href="https://developer.android.com/studio">Android Studio</a> recommended)</em>.</p>
</li>
<li>
<p>Run <a href="https://developer.android.com/agi">AGI</a> and follow instructions to profile the app/system
with trace capture(s). See https://developer.android.com/agi/start for more details to
get started.</p>
<ul>
<li>We typically only run "Capture System Profiler trace" <em>(not necessarily "Capture Frame Profiler trace")</em></li>
<li>When configuring the trace:
<ul>
<li>For both the WebGPU and Vulkan backends configure the profiler for the Vulkan API
<em>(since WebGPU should be using Vulkan under the hood as well)</em></li>
<li>Running for ~1 seconds should suffice</li>
<li>Hit the "Configure" button in Trace objects, select "Switch to advanced mode" and add:
<pre><code>data_sources {
config {
name: "track_event"
track_event_config {
disabled_categories: "*"
enabled_categories: "filament/filament"
enabled_categories: "filament/jobsystem"
enabled_categories: "filament/gltfio"
}
}
}
</code></pre>
</li>
</ul>
</li>
<li>One you open the trace, zoom into a series of frames to get a sense of generally how long they typically take
<em>(use <code>W</code>, <code>S</code>, <code>A</code> and <code>D</code> keys and mouse wheel for navigation)</em> and find a representative one.
We are most interested in the performance of the
<code>FEngine::loop</code> thread, how long it takes, overlap in activities/processes/commands, reduction in queue submissions,
etc. Similarly, we can view GPU timeline as it relates to that. We want to see overlapping
shader invocations and non-interrupted fragment shader runs.</li>
</ul>
</li>
</ol>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/coverage.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/framegraph.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/coverage.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/framegraph.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+31 -27
View File
@@ -995,10 +995,10 @@ Value
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
mobile), `low`, `medium`, `high`. The type must be one of the types described in
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
Type | Description
:----------------------|:---------------------------------
@@ -1096,30 +1096,37 @@ Value
`bool` or `number`, depending on the `type` of the constant. The type must be one of the types
described in table [materialConstantsTypes].
Type | Description | Default
:----------------------|:-----------------------------------------|:------------------
int | A signed, 32 bit GLSL int | 0
float | A single-precision GLSL float | 0.0
bool | A GLSL bool | false
Constants may also be specified as mutable by setting the `mutable` property to `true`. Only
`bool` spec constants may be specified as mutable.
| Type | Description | Default | May be mutable? |
|:------|:------------------------------|:--------|-----------------|
| int | A signed, 32 bit GLSL int | | no |
| float | A single-precision GLSL float | 0.0 | no |
| bool | A GLSL bool | false | yes |
[Table [materialConstantsTypes]: Material constants types]
Description
: Lists the constant parameters accepted by your material. These constants can be set, or
"specialized", at runtime when loading a material package. Multiple materials can be loaded from
the same material package with differing constant parameter specializations. Once a material is
loaded from a material package, its constant parameters cannot be changed. Compared to regular
parameters, constant parameters allow the compiler to generate more efficient code. Access
constant parameters from the shader by prefixing the name with `materialConstant_`. For example,
a constant parameter named `myConstant` is accessed in the shader as
`materialConstant_myConstant`. If a constant parameter is not set at runtime, the default is
used.
the same material package with differing constant parameter specializations. If a constant
parameter is specialized as mutable, it may be changed at any time on a per-instance basis via
`MaterialInstance::setConstant(name, value)`. Otherwise, once a material is loaded from a
material package, its constant parameters cannot be changed.
Compared to regular parameters, constant parameters allow the compiler to generate more
efficient code. Access constant parameters from the shader by prefixing the name with
`materialConstant_`. For example, a constant parameter named `myConstant` is accessed in the
shader as `materialConstant_myConstant`. If a constant parameter is not set at runtime, the
default is used.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
constants : [
{
name : overrideAlpha,
type : bool
type : bool,
mutable : true,
},
{
name : customAlpha,
@@ -2476,17 +2483,14 @@ type aliases:
### Matrices
Name | Type | Description
:-----------------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getEyeFromViewMatrix()** | float4x4 | Matrix that converts from view space to eye space
**getEyeFromViewMatrix(int eyeIndex)** | float4x4 | Matrix that converts from view space to eye space for the eye referred to by eyeIndex
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getClipFromWorldMatrix(int eyeIndex)** | float4x4 | Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
### Frame constants
-1
View File
@@ -24,7 +24,6 @@
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
- [Using Instruments on macOS](./notes/instruments.md)
- [Code coverage analysis](./notes/coverage.md)
- [Performance analysis](./notes/performance_analysis.md)
- [Framegraph](./notes/framegraph.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
@@ -6,64 +6,12 @@
- Download and install Android GPU Inspector (AGI). See https://developer.android.com/agi.
### Android with the Vulkan Backend
---
#### Profiling
1. Before profiling the application or analyzing the performance in a consistent way, ideally
the **GPU frequency on the target hardware should get locked**. In order to do this, you need to do the following:
1. Ensure your device is OEM unlocked. If your phone is carrier-locked, you may need
to wait a period, such as 60 or 90 days after activation to be eligible for unlocking.
Some phones don't support this at all. You will need to enable developer options
(e.g. Settings > About Phone and tap the Build number 7 times). You need to go to
Settings > System > Developer options and toggle on "OEM unlocking".
1. Next, you need to unlock the phone. You will need to install Android SDK Platform
Tools on you computer, enable "USB debugging" in your phone's Settings > System > Developer options.
1. Connect the phone to the computer via a USB cable and run from the command line:
```shell
adb reboot bootloader
# once the phone is in bootloader mode, run the following to begin the unlocking
# process:
fastboot flashing unlock
```
A warning will appear on your phone's screen. Use the volume buttons to navigate and
the power button to select the "Unlock the bootloader" option. The phone will perform
a factory data reset and reboot with an unlocked bootloader.
1. You would need to flash an image to the phone with root permissions, such as a *-userdebug or *-eng
build. One way to do this is with the [Android Flash Tool](https://flash.android.com/). Connect the
tool to your device and find a build to flash ending in `-userdebug` or `-eng`. Once you have that
selected run `Install build`.
1. Shell into your device as root and configure the gpu frequency to be locked, e.g.:
```shell
adb shell
su
# navigate to the system GPU directory. this varies on different phones. One phone might have
# it at /sys/class/kgsl/kgsl-3d0 and another might be in something similar, maybe with "mali" instead
# of "kgsl". At the time of writing this for the device at hand it was /sys/devices/platform/1f000000.mali
cd /sys/devices/platform/1f000000.mali
# get the current available GPU governors and frequencies.
# note that some systems may have these at gpu_available_governors and gpu_available_frequencies, but
# the system at the time of writing this had available_governors and available_frequences
cat available_governors
cat available_frequencies
# depending on the governors, you may want to set it prioritize performance over other things like
# battery. Some systems allow you to do this with something like (although, for the device used at the
# time of writing this did not have an equivalent option):
echo performance > gpu_governor
# finally, lock your frequency in, usually to something high like 897 MHz. Some systems may have you
# pipe the value to gpu_min_freq and gpu_max_freq, but the system used at the time of writing this had:
echo 940000 > hint_min_freq
echo 940000 > hint_max_freq
# you can typically verify the GPU is running at that frequency consistently by running something like
# the following a few times over time, which should show the frequency you want to lock the device to:
cat cur_freq
```
1. You may need to re-apply the `hint_min_freq` just before starting the profiling trace and check before and after
that the frequency remained at the value expected. Some systems may adjust the frequency on you, but you
may want to ensure the frequency remains the same through the analysis.
1. The GPU frequency settings should be undone after restarting the device, but after you have done your app profiling,
you can revert the state of the device, such as the OS build image, back to the way you had it
initially, as needed.
1. Build a release build of Filament with the applicable backend(s) enabled
_(+ any special flags for enabling sys strace. Nothing special is needed for Vulkan or WebGPU aside from
building a release build with no flags)_ _(debug builds for this are useless)_
+4 -10
View File
@@ -494,6 +494,9 @@ else()
-Wover-aligned -Wreorder-init-list
-Werror
)
if (CMAKE_CXX_STANDARD EQUAL 20)
list(APPEND FILAMENT_WARNINGS -Wno-deprecated-this-capture)
endif()
endif()
if (APPLE)
@@ -577,9 +580,7 @@ if (APPLE OR LINUX)
test/test_Template.cpp
)
if (FILAMENT_SUPPORTS_WEBGPU)
list(APPEND BACKEND_TEST_SRC
test/test_WebGPUAsyncTaskCounter.cpp
test/test_WebGPUComposeSwizzle.cpp)
list(APPEND BACKEND_TEST_SRC test/test_WebGPUAsyncTaskCounter.cpp)
endif()
if (APPLE)
# Metal-specific tests
@@ -628,10 +629,6 @@ if (APPLE AND NOT IOS)
target_link_libraries(backend_test PRIVATE image imageio)
list(APPEND BACKEND_TEST_DEPS image)
endif()
if (FILAMENT_SUPPORTS_WEBGPU)
target_link_libraries(backend_test PRIVATE webgpu_dawn dawncpp_headers)
list(APPEND BACKEND_TEST_DEPS webgpu_dawn dawncpp_headers)
endif()
set(BACKEND_TEST_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libbackendtest_combined.a")
combine_static_libs(backend_test "${BACKEND_TEST_COMBINED_OUTPUT}" "${BACKEND_TEST_DEPS}")
@@ -663,9 +660,6 @@ if (LINUX)
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
if (FILAMENT_SUPPORTS_WEBGPU)
target_link_libraries(backend_test_linux PRIVATE webgpu_dawn dawncpp_headers)
endif()
endif()
# ==================================================================================================
@@ -629,18 +629,6 @@ enum class PrimitiveType : uint8_t {
TRIANGLE_STRIP = 5 //!< triangle strip
};
[[nodiscard]] constexpr bool isStripPrimitiveType(const PrimitiveType type) {
switch (type) {
case PrimitiveType::POINTS:
case PrimitiveType::LINES:
case PrimitiveType::TRIANGLES:
return false;
case PrimitiveType::LINE_STRIP:
case PrimitiveType::TRIANGLE_STRIP:
return true;
}
}
/**
* Supported uniform types
*/
@@ -27,12 +27,12 @@ namespace filament::backend {
* A PresentCallable is a callable object that, when called, schedules a frame for presentation on
* a SwapChain.
*
* Typically, Filament's backend is responsible for scheduling a frame's presentation. However,
* there are certain cases where the application might want to control when a frame is scheduled for
* Typically, Filament's backend is responsible scheduling a frame's presentation. However, there
* are certain cases where the application might want to control when a frame is scheduled for
* presentation.
*
* For example, on iOS, UIKit elements can be synchronized to 3D content by scheduling a present
* within a CATransaction:
* within a CATransation:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* void myFrameScheduledCallback(PresentCallable presentCallable, void* user) {
@@ -55,13 +55,12 @@ namespace filament::backend {
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @remark The PresentCallable mechanism for user-controlled presentation is only supported by
* Filament's Metal backend. On other backends, the FrameScheduledCallback is still invoked, but the
* PresentCallable passed to it is a no-op and calling it has no effect.
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
* backends ignore the callback (which will never be called) and proceed normally.
*
* When using the Metal backend, applications *must* call each PresentCallable they receive. Each
* PresentCallable represents a frame that is waiting to be presented, and failing to call it
* will result in a memory leak. To "cancel" the presentation of a frame, pass false to the
* Applications *must* call each PresentCallable they receive. Each PresentCallable represents a
* frame that is waiting to be presented. If an application fails to call a PresentCallable, a
* memory leak could occur. To "cancel" the presentation of a frame, pass false to the
* PresentCallable, which will cancel the presentation of the frame and release associated memory.
*
* @see Renderer, SwapChain::setFrameScheduledCallback
@@ -70,7 +69,6 @@ class UTILS_PUBLIC PresentCallable {
public:
using PresentFn = void(*)(bool presentFrame, void* user);
static void noopPresent(bool, void*) {}
PresentCallable(PresentFn fn, void* user) noexcept;
~PresentCallable() noexcept = default;
+4 -1
View File
@@ -20,6 +20,7 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/bitset.h>
#include <backend/DriverEnums.h>
@@ -66,6 +67,7 @@ public:
using DescriptorBindingsInfo = utils::FixedCapacityVector<Descriptor>;
using DescriptorSetInfo = std::array<DescriptorBindingsInfo, MAX_DESCRIPTOR_SET_COUNT>;
using SpecializationConstantsInfo = utils::FixedCapacityVector<SpecializationConstant>;
using MutableSpecConstantsInfo = utils::bitset8;
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
@@ -103,7 +105,8 @@ public:
Program& descriptorBindings(backend::descriptor_set_t set,
DescriptorBindingsInfo descriptorBindings) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept;
struct PushConstant {
utils::CString name;
@@ -19,16 +19,6 @@
#include <backend/Platform.h>
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_X11)
// Resolve the conflicts between webgpu_cpp.h and X11 defines
#undef Always
#undef Success
#undef None
#undef True
#undef False
#undef Status
#undef Bool
#endif
#include <webgpu/webgpu_cpp.h>
#include <cstdint>
@@ -107,10 +107,6 @@
#define DECL_DRIVER_API_R_N(R, N, ...) \
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
#define DECL_DRIVER_API_TAGGED_R_N(R, N, ...) \
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString, tag = {}), \
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString, tag))
#define DECL_DRIVER_API_SYNCHRONOUS_N(R, N, ...) \
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
@@ -169,31 +165,35 @@ DECL_DRIVER_API_0(finish)
// reset state tracking, if the driver does any state tracking (e.g. GL)
DECL_DRIVER_API_0(resetState)
DECL_DRIVER_API_N(setDebugTag,
backend::HandleBase::HandleId, handleId,
utils::CString, tag)
/*
* Creating driver objects
* -----------------------
*/
DECL_DRIVER_API_TAGGED_R_N(backend::VertexBufferInfoHandle, createVertexBufferInfo,
DECL_DRIVER_API_R_N(backend::VertexBufferInfoHandle, createVertexBufferInfo,
uint8_t, bufferCount,
uint8_t, attributeCount,
backend::AttributeArray, attributes)
DECL_DRIVER_API_TAGGED_R_N(backend::VertexBufferHandle, createVertexBuffer,
DECL_DRIVER_API_R_N(backend::VertexBufferHandle, createVertexBuffer,
uint32_t, vertexCount,
backend::VertexBufferInfoHandle, vbih)
DECL_DRIVER_API_TAGGED_R_N(backend::IndexBufferHandle, createIndexBuffer,
DECL_DRIVER_API_R_N(backend::IndexBufferHandle, createIndexBuffer,
backend::ElementType, elementType,
uint32_t, indexCount,
backend::BufferUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::BufferObjectHandle, createBufferObject,
DECL_DRIVER_API_R_N(backend::BufferObjectHandle, createBufferObject,
uint32_t, byteCount,
backend::BufferObjectBinding, bindingType,
backend::BufferUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTexture,
backend::SamplerType, target,
uint8_t, levels,
backend::TextureFormat, format,
@@ -203,19 +203,19 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTexture,
uint32_t, depth,
backend::TextureUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureView,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureView,
backend::TextureHandle, texture,
uint8_t, baseLevel,
uint8_t, levelCount)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureViewSwizzle,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle,
backend::TextureHandle, texture,
backend::TextureSwizzle, r,
backend::TextureSwizzle, g,
backend::TextureSwizzle, b,
backend::TextureSwizzle, a)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage2,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage2,
backend::SamplerType, target,
backend::TextureFormat, format,
uint32_t, width,
@@ -223,7 +223,7 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage2,
backend::TextureUsage, usage,
backend::Platform::ExternalImageHandleRef, image)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage,
backend::SamplerType, target,
backend::TextureFormat, format,
uint32_t, width,
@@ -231,7 +231,7 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImage,
backend::TextureUsage, usage,
void*, image)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImagePlane,
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImagePlane,
backend::TextureFormat, format,
uint32_t, width,
uint32_t, height,
@@ -239,7 +239,7 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, createTextureExternalImagePla
void*, image,
uint32_t, plane)
DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTexture,
DECL_DRIVER_API_R_N(backend::TextureHandle, importTexture,
intptr_t, id,
backend::SamplerType, target,
uint8_t, levels,
@@ -250,17 +250,17 @@ DECL_DRIVER_API_TAGGED_R_N(backend::TextureHandle, importTexture,
uint32_t, depth,
backend::TextureUsage, usage)
DECL_DRIVER_API_TAGGED_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
DECL_DRIVER_API_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
backend::VertexBufferHandle, vbh,
backend::IndexBufferHandle, ibh,
backend::PrimitiveType, pt)
DECL_DRIVER_API_TAGGED_R_N(backend::ProgramHandle, createProgram,
DECL_DRIVER_API_R_N(backend::ProgramHandle, createProgram,
backend::Program&&, program)
DECL_DRIVER_API_TAGGED_R_N(backend::RenderTargetHandle, createDefaultRenderTarget)
DECL_DRIVER_API_R_0(backend::RenderTargetHandle, createDefaultRenderTarget)
DECL_DRIVER_API_TAGGED_R_N(backend::RenderTargetHandle, createRenderTarget,
DECL_DRIVER_API_R_N(backend::RenderTargetHandle, createRenderTarget,
backend::TargetBufferFlags, targetBufferFlags,
uint32_t, width,
uint32_t, height,
@@ -270,23 +270,23 @@ DECL_DRIVER_API_TAGGED_R_N(backend::RenderTargetHandle, createRenderTarget,
backend::TargetBufferInfo, depth,
backend::TargetBufferInfo, stencil)
DECL_DRIVER_API_TAGGED_R_N(backend::FenceHandle, createFence)
DECL_DRIVER_API_R_0(backend::FenceHandle, createFence)
DECL_DRIVER_API_TAGGED_R_N(backend::SwapChainHandle, createSwapChain,
DECL_DRIVER_API_R_N(backend::SwapChainHandle, createSwapChain,
void*, nativeWindow,
uint64_t, flags)
DECL_DRIVER_API_TAGGED_R_N(backend::SwapChainHandle, createSwapChainHeadless,
DECL_DRIVER_API_R_N(backend::SwapChainHandle, createSwapChainHeadless,
uint32_t, width,
uint32_t, height,
uint64_t, flags)
DECL_DRIVER_API_TAGGED_R_N(backend::TimerQueryHandle, createTimerQuery)
DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery)
DECL_DRIVER_API_TAGGED_R_N(backend::DescriptorSetLayoutHandle, createDescriptorSetLayout,
DECL_DRIVER_API_R_N(backend::DescriptorSetLayoutHandle, createDescriptorSetLayout,
backend::DescriptorSetLayout&&, info)
DECL_DRIVER_API_TAGGED_R_N(backend::DescriptorSetHandle, createDescriptorSet,
DECL_DRIVER_API_R_N(backend::DescriptorSetHandle, createDescriptorSet,
backend::DescriptorSetLayoutHandle, dslh)
DECL_DRIVER_API_N(updateDescriptorSetBuffer,
@@ -337,8 +337,8 @@ DECL_DRIVER_API_N(destroyDescriptorSet, backend::DescriptorSetHandle, ds
*/
DECL_DRIVER_API_SYNCHRONOUS_0(void, terminate)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::StreamHandle, createStreamNative, void*, stream, utils::CString, tag)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::StreamHandle, createStreamAcquired, utils::CString, tag)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::StreamHandle, createStreamNative, void*, stream)
DECL_DRIVER_API_SYNCHRONOUS_0(backend::StreamHandle, createStreamAcquired)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setAcquiredImage, backend::StreamHandle, stream, void*, image, const math::mat3f&, transform, backend::CallbackHandler*, handler, backend::StreamCallback, cb, void*, userData)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setStreamDimensions, backend::StreamHandle, stream, uint32_t, width, uint32_t, height)
DECL_DRIVER_API_SYNCHRONOUS_N(int64_t, getStreamTimestamp, backend::StreamHandle, stream)
@@ -249,9 +249,8 @@ public:
}
void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
if (tag.empty()) {
return;
}
// TODO: for now, only pool handles check for use-after-free, so we only keep tags for
// those
uint32_t key = id;
if (UTILS_LIKELY(isPoolHandle(id))) {
// Truncate the age to get the debug tag
-24
View File
@@ -38,11 +38,6 @@
#include <stdlib.h>
#include <string.h>
#if defined(WIN32)
# include <windows.h> // for VirtualAlloc, VirtualProtect, VirtualFree
# include <utils/unwindows.h>
#endif
using namespace utils;
namespace filament::backend {
@@ -139,21 +134,6 @@ void* CircularBuffer::alloc(size_t size) {
mprotect(guard, BLOCK_SIZE, PROT_NONE);
}
return data;
#elif defined(WIN32)
size_t const BLOCK_SIZE = getBlockSize();
// On Windows, use VirtualAlloc instead of malloc to allocate virtual memory.
// This allows us to set page protection by VirtualProtect.
void* data = VirtualAlloc(nullptr, size * 2 + BLOCK_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
FILAMENT_CHECK_POSTCONDITION(data != nullptr)
<< "couldn't allocate " << (size * 2 / 1024)
<< " KiB of virtual address space for the command buffer";
// guard page at the end
void* guard = (void*)(uintptr_t(data) + size * 2);
DWORD oldProtect = 0;
BOOL ok = VirtualProtect(guard, BLOCK_SIZE, PAGE_NOACCESS, &oldProtect);
FILAMENT_CHECK_POSTCONDITION(ok) << "VirtualProtect failed to set guard page";
return data;
#else
return ::malloc(2 * size);
#endif
@@ -170,10 +150,6 @@ void CircularBuffer::dealloc() noexcept {
mAshmemFd = -1;
}
}
#elif defined(WIN32)
if (mData) {
VirtualFree(mData, 0, MEM_RELEASE);
}
#else
::free(mData);
#endif
+5 -5
View File
@@ -57,7 +57,7 @@ static void printParameterPack(io::ostream& out, const FIRST& first, const REMAI
printParameterPack(out, rest...);
}
static UTILS_NOINLINE UTILS_UNUSED std::string_view extractMethodName(std::string_view command) noexcept {
static UTILS_NOINLINE UTILS_UNUSED std::string extractMethodName(std::string& command) noexcept {
constexpr const char startPattern[] = "::Command<&filament::backend::Driver::";
auto pos = command.rfind(startPattern);
auto end = command.rfind('(');
@@ -133,9 +133,9 @@ template<std::size_t... I>
void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log(std::index_sequence<I...>) noexcept {
#if DEBUG_COMMAND_STREAM
static_assert(UTILS_HAS_RTTI, "DEBUG_COMMAND_STREAM can only be used with RTTI");
CString command = CallStack::demangleTypeName(typeid(Command).name());
DLOG(INFO) << extractMethodName({command.data(), command.size()}) << " : size=" << sizeof(Command);
io::sstream parameterPack;
std::string command = utils::CallStack::demangleTypeName(typeid(Command).name()).c_str();
DLOG(INFO) << extractMethodName(command) << " : size=" << sizeof(Command);
utils::io::sstream parameterPack;
printParameterPack(parameterPack, std::get<I>(mArgs)...);
DLOG(INFO) << "\t" << parameterPack.c_str();
#endif
@@ -164,7 +164,7 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log() noexcept {
// ------------------------------------------------------------------------------------------------
void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) {
*next = align(sizeof(CustomCommand));
*next = CustomCommand::align(sizeof(CustomCommand));
static_cast<CustomCommand*>(base)->mCommand();
static_cast<CustomCommand*>(base)->~CustomCommand();
}
+6 -7
View File
@@ -21,8 +21,7 @@
#include <utils/ostream.h>
#ifndef NDEBUG
# include <utils/CString.h>
# include <string_view>
# include <string>
#endif
#include <stddef.h>
@@ -37,11 +36,11 @@ static char const * const kOurNamespace = "filament::backend::";
// removes all occurrences of "what" from "str"
UTILS_NOINLINE
static CString& removeAll(CString& str, const std::string_view what) noexcept {
static std::string& removeAll(std::string& str, const std::string& what) noexcept {
if (!what.empty()) {
const CString empty;
const std::string empty;
size_t pos = 0;
while ((pos = std::string_view{ str.data(), str.size() }.find(what, pos)) != std::string_view::npos) {
while ((pos = str.find(what, pos)) != std::string::npos) {
str.replace(pos, what.length(), empty);
}
}
@@ -50,13 +49,13 @@ static CString& removeAll(CString& str, const std::string_view what) noexcept {
template <typename T>
UTILS_NOINLINE
static io::ostream& logHandle(io::ostream& out, CString& typeName, T id) noexcept {
static io::ostream& logHandle(io::ostream& out, std::string& typeName, T id) noexcept {
return out << removeAll(typeName, kOurNamespace) << " @ " << id;
}
template <typename T>
io::ostream& operator<<(io::ostream& out, const Handle<T>& h) noexcept {
CString s{ CallStack::typeName<Handle<T>>() };
std::string s(CallStack::typeName<Handle<T>>().c_str());
return logHandle(out, s, h.getId());
}
+13 -2
View File
@@ -82,8 +82,19 @@ Program& Program::attributes(AttributesInfo attributes) noexcept {
return *this;
}
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants) noexcept {
mSpecializationConstants = std::move(specConstants);
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept {
// String the two lists together.
mSpecializationConstants = SpecializationConstantsInfo(
specConstants.size() + mutableSpecConstants.size());
std::uninitialized_move(specConstants.begin(), specConstants.end(),
mSpecializationConstants.begin());
for (uint32_t i = 0; i < mutableSpecConstants.size(); i++) {
mSpecializationConstants[i + specConstants.size()] = SpecializationConstant {
.id = i + firstMutableId,
.value = mutableSpecConstants[i],
};
}
return *this;
}
+50 -55
View File
@@ -418,40 +418,49 @@ void MetalDriver::finish(int) {
}
void MetalDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes, utils::CString tag) {
uint8_t attributeCount, AttributeArray attributes) {
construct_handle<MetalVertexBufferInfo>(vbih, *mContext,
bufferCount, attributeCount, attributes);
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
}
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::CString tag) {
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih) {
MetalVertexBufferInfo const* const vbi = handle_cast<const MetalVertexBufferInfo>(vbih);
construct_handle<MetalVertexBuffer>(vbh, *mContext, vertexCount, vbi->bufferCount, vbih);
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
// No actual GPU memory is allocated here, so no need to check for allocation success.
}
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, utils::CString tag) {
uint32_t indexCount, BufferUsage usage) {
auto elementSize = (uint8_t)getElementTypeSize(elementType);
auto* indexBuffer =
construct_handle<MetalIndexBuffer>(ibh, *mContext, usage, elementSize, indexCount);
auto& buffer = indexBuffer->buffer;
FILAMENT_CHECK_POSTCONDITION(buffer.wasAllocationSuccessful())
<< "Could not allocate Metal index buffer of size " << buffer.getSize()
<< ", tag=" << tag.c_str_safe();
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
// If the allocation was not successful, postpone the error message until the next tick, to give
// Filament a chance to call setDebugTag on the handle; this way we get a nicer error message.
if (UTILS_UNLIKELY(!buffer.wasAllocationSuccessful())) {
const size_t byteCount = buffer.getSize();
runAtNextTick([byteCount, this, ibh]() {
FILAMENT_CHECK_POSTCONDITION(false)
<< "Could not allocate Metal index buffer of size " << byteCount
<< ", tag=" << mHandleAllocator.getHandleTag(ibh.getId()).c_str_safe();
});
}
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
BufferObjectBinding bindingType, BufferUsage usage) {
auto* bufferObject =
construct_handle<MetalBufferObject>(boh, *mContext, bindingType, usage, byteCount);
FILAMENT_CHECK_POSTCONDITION(bufferObject->getBuffer()->wasAllocationSuccessful())
<< "Could not allocate Metal buffer of size " << byteCount
<< ", tag=" << tag.c_str_safe();
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
// If the allocation was not successful, postpone the error message until the next tick, to give
// Filament a chance to call setDebugTag on the handle; this way we get a nicer error message.
if (UTILS_UNLIKELY(!bufferObject->getBuffer()->wasAllocationSuccessful())) {
runAtNextTick([byteCount, this, boh]() {
FILAMENT_CHECK_POSTCONDITION(false)
<< "Could not allocate Metal buffer of size " << byteCount
<< ", tag=" << mHandleAllocator.getHandleTag(boh.getId()).c_str_safe();
});
}
}
// fixme: TextureUsage is a bitfield
@@ -486,7 +495,7 @@ inline const char* stringify(SamplerType samplerType) {
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString tag) {
uint32_t depth, TextureUsage usage) {
// Clamp sample count to what the device supports.
auto& sc = mContext->sampleCountLookup;
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
@@ -498,60 +507,55 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
"createTextureR(th = %d, target = %s, levels = %d, format = ?, samples = %d, width = "
"%d, height = %d, depth = %d, usage = %s)\n",
th.getId(), stringify(target), levels, samples, width, height, depth, stringify(usage));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
void MetalDriver::createTextureViewR(
Handle<HwTexture> th, Handle<HwTexture> srch, uint8_t baseLevel, uint8_t levelCount) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
mContext->textures.insert(
construct_handle<MetalTexture>(th, *mContext, src, baseLevel, levelCount));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, utils::CString tag) {
backend::TextureSwizzle a) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef image, utils::CString tag) {
Platform::ExternalImageHandleRef image) {
// FIXME: implement createTextureExternalImage2R
}
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, utils::CString tag) {
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane, utils::CString tag) {
void* image, uint32_t plane) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image, plane));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString tag) {
uint32_t depth, TextureUsage usage) {
id<MTLTexture> metalTexture = (id<MTLTexture>) CFBridgingRelease((void*) i);
FILAMENT_CHECK_PRECONDITION(metalTexture.width == width)
<< "Imported id<MTLTexture> width (" << metalTexture.width
@@ -568,36 +572,32 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
<< ") != Filament texture type (" << filamentMetalType << ")";
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext,
target, levels, format, samples, width, height, depth, usage, metalTexture));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString tag) {
PrimitiveType pt) {
construct_handle<MetalRenderPrimitive>(rph);
MetalDriver::setRenderPrimitiveBuffer(rph, pt, vbh, ibh);
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::CString tag) {
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
#if FILAMENT_METAL_DEBUG_LOG
auto handleId = rph.getId();
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
DLOG(INFO) << program;
#endif
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString tag) {
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
construct_handle<MetalRenderTarget>(rth, mContext);
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, uint8_t layerCount, MRT color,
TargetBufferInfo depth, TargetBufferInfo stencil, utils::CString tag) {
TargetBufferInfo depth, TargetBufferInfo stencil) {
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
<< "createRenderTarget must be called outside of a render pass.";
// Clamp sample count to what the device supports.
@@ -640,18 +640,14 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
construct_handle<MetalRenderTarget>(rth, mContext, width, height, samples,
colorAttachments, depthAttachment, stencilAttachment);
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void MetalDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
void MetalDriver::createFenceR(Handle<HwFence> fh, int dummy) {
auto* fence = handle_cast<MetalFence>(fh);
fence->encode();
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
}
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
utils::CString tag) {
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow;
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, pixelBuffer, flags);
@@ -662,18 +658,15 @@ void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow;
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, metalLayer, flags);
}
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
}
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
uint32_t width, uint32_t height, uint64_t flags, utils::CString tag) {
uint32_t width, uint32_t height, uint64_t flags) {
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, width, height, flags);
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
}
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
// nothing to do, timer query was constructed in createTimerQueryS
mHandleAllocator.associateTagToHandle(tqh.getId(), std::move(tag));
}
UTILS_UNUSED
@@ -710,7 +703,7 @@ const char* toString(DescriptorFlags flags) {
}
void MetalDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info, utils::CString tag) {
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info) {
#if FILAMENT_METAL_DEBUG_LOG == 1
const char* labelStr = "";
std::visit([&labelStr](auto&& arg) {
@@ -731,15 +724,13 @@ void MetalDriver::createDescriptorSetLayoutR(
DEBUG_LOG("})\n");
#endif
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
mHandleAllocator.associateTagToHandle(dslh.getId(), std::move(tag));
}
void MetalDriver::createDescriptorSetR(
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh, utils::CString tag) {
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh) {
DEBUG_LOG("createDescriptorSetR(dsh = %d, dslh = %d)\n", dsh.getId(), dslh.getId());
MetalDescriptorSetLayout* layout = handle_cast<MetalDescriptorSetLayout>(dslh);
construct_handle<MetalDescriptorSet>(dsh, layout);
mHandleAllocator.associateTagToHandle(dsh.getId(), std::move(tag));
}
Handle<HwVertexBufferInfo> MetalDriver::createVertexBufferInfoS() noexcept {
@@ -978,11 +969,11 @@ ShaderLanguage MetalDriver::getShaderLanguage() const noexcept {
return ShaderLanguage::MSL;
}
Handle<HwStream> MetalDriver::createStreamNative(void* stream, utils::CString tag) {
Handle<HwStream> MetalDriver::createStreamNative(void* stream) {
return {};
}
Handle<HwStream> MetalDriver::createStreamAcquired(utils::CString tag) {
Handle<HwStream> MetalDriver::createStreamAcquired() {
return {};
}
@@ -2144,6 +2135,10 @@ void MetalDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
void MetalDriver::resetState(int) {
}
void MetalDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
void MetalDriver::runAtNextTick(const std::function<void()>& fn) noexcept {
mTickOps.push_back(fn);
}
+5 -2
View File
@@ -125,11 +125,11 @@ void NoopDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh) {
void NoopDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
}
Handle<HwStream> NoopDriver::createStreamNative(void* nativeStream, utils::CString tag) {
Handle<HwStream> NoopDriver::createStreamNative(void* nativeStream) {
return {};
}
Handle<HwStream> NoopDriver::createStreamAcquired(utils::CString tag) {
Handle<HwStream> NoopDriver::createStreamAcquired() {
return {};
}
@@ -415,4 +415,7 @@ void NoopDriver::bindDescriptorSet(
backend::DescriptorSetOffsetArray&& offsets) {
}
void NoopDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
}
} // namespace filament
+34 -73
View File
@@ -639,29 +639,24 @@ void OpenGLDriver::createVertexBufferInfoR(
Handle<HwVertexBufferInfo> vbih,
uint8_t bufferCount,
uint8_t attributeCount,
AttributeArray attributes,
utils::CString tag) {
AttributeArray attributes) {
DEBUG_MARKER()
construct<GLVertexBufferInfo>(vbih, bufferCount, attributeCount, attributes);
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
}
void OpenGLDriver::createVertexBufferR(
Handle<HwVertexBuffer> vbh,
uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih,
utils::CString tag) {
Handle<HwVertexBufferInfo> vbih) {
DEBUG_MARKER()
construct<GLVertexBuffer>(vbh, vertexCount, vbih);
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
}
void OpenGLDriver::createIndexBufferR(
Handle<HwIndexBuffer> ibh,
ElementType elementType,
uint32_t indexCount,
BufferUsage usage,
utils::CString tag) {
BufferUsage usage) {
DEBUG_MARKER()
auto& gl = mContext;
@@ -673,11 +668,10 @@ void OpenGLDriver::createIndexBufferR(
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, getBufferUsage(usage));
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
}
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
uint32_t byteCount, BufferObjectBinding bindingType, BufferUsage usage) {
DEBUG_MARKER()
assert_invariant(byteCount > 0);
@@ -699,12 +693,11 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
}
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
}
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString tag) {
PrimitiveType pt) {
DEBUG_MARKER()
auto& gl = mContext;
@@ -737,10 +730,9 @@ void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::CString tag) {
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
DEBUG_MARKER()
@@ -768,7 +760,6 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
construct<OpenGLProgram>(ph, *this, std::move(program));
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(ph.getId(), std::move(tag));
}
UTILS_NOINLINE
@@ -873,7 +864,7 @@ void OpenGLDriver::textureStorage(GLTexture* t,
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, utils::CString tag) {
TextureUsage usage) {
DEBUG_MARKER()
GLenum internalFormat = getInternalFormat(format);
@@ -962,11 +953,10 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
}
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
Handle<HwTexture> srch, uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
Handle<HwTexture> srch, uint8_t baseLevel, uint8_t levelCount) {
DEBUG_MARKER()
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
@@ -1009,12 +999,10 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
ref->count++;
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a,
utils::CString tag) {
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
DEBUG_MARKER()
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
@@ -1074,12 +1062,11 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
ref->count++;
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
Platform::ExternalImageHandleRef image, utils::CString tag) {
Platform::ExternalImageHandleRef image) {
DEBUG_MARKER()
usage |= TextureUsage::SAMPLEABLE;
@@ -1126,12 +1113,10 @@ void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerTyp
t->gl.target = t->externalTexture->target;
t->gl.id = t->externalTexture->id;
}
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType target,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image,
utils::CString tag) {
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) {
DEBUG_MARKER()
usage |= TextureUsage::SAMPLEABLE;
@@ -1177,18 +1162,17 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
t->gl.target = t->externalTexture->target;
t->gl.id = t->externalTexture->id;
}
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
void* image, uint32_t plane, utils::CString tag) {
void* image, uint32_t plane) {
// not relevant for the OpenGL backend
}
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
uint32_t w, uint32_t h, uint32_t depth, TextureUsage usage, utils::CString tag) {
uint32_t w, uint32_t h, uint32_t depth, TextureUsage usage) {
DEBUG_MARKER()
auto& gl = mContext;
@@ -1241,7 +1225,6 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
}
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
@@ -1643,7 +1626,7 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
}
void OpenGLDriver::createDefaultRenderTargetR(
Handle<HwRenderTarget> rth, utils::CString tag) {
Handle<HwRenderTarget> rth, int) {
DEBUG_MARKER()
construct<GLRenderTarget>(rth, 0, 0); // FIXME: we don't know the width/height
@@ -1654,7 +1637,6 @@ void OpenGLDriver::createDefaultRenderTargetR(
rt->gl.samples = 1;
// FIXME: these flags should reflect the actual attachments present
rt->targets = TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH;
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
@@ -1665,8 +1647,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
uint8_t layerCount,
MRT color,
TargetBufferInfo depth,
TargetBufferInfo stencil,
utils::CString tag) {
TargetBufferInfo stencil) {
DEBUG_MARKER()
GLRenderTarget* rt = construct<GLRenderTarget>(rth, width, height);
@@ -1779,10 +1760,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
assert_invariant(tmin == tmax);
CHECK_GL_ERROR()
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void OpenGLDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
void OpenGLDriver::createFenceR(Handle<HwFence> fh, int) {
DEBUG_MARKER()
GLFence* f = handle_cast<GLFence*>(fh);
@@ -1804,11 +1784,9 @@ void OpenGLDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
});
}
#endif
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
}
void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
utils::CString tag) {
void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
DEBUG_MARKER()
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
@@ -1825,12 +1803,10 @@ void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
sc->rec709 = ((flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) &&
!mPlatform.isSRGBSwapChainSupported());
}
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
}
void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
uint32_t width, uint32_t height, uint64_t flags, utils::CString tag) {
uint32_t width, uint32_t height, uint64_t flags) {
DEBUG_MARKER()
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
@@ -1848,30 +1824,25 @@ void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
sc->rec709 = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE &&
!mPlatform.isSRGBSwapChainSupported());
}
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
}
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
DEBUG_MARKER()
GLTimerQuery* tq = handle_cast<GLTimerQuery*>(tqh);
mContext.createTimerQuery(tq);
mHandleAllocator.associateTagToHandle(tqh.getId(), std::move(tag));
}
void OpenGLDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
DescriptorSetLayout&& info, utils::CString tag) {
DescriptorSetLayout&& info) {
DEBUG_MARKER()
construct<GLDescriptorSetLayout>(dslh, std::move(info));
mHandleAllocator.associateTagToHandle(dslh.getId(), std::move(tag));
}
void OpenGLDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh, utils::CString tag) {
Handle<HwDescriptorSetLayout> dslh) {
DEBUG_MARKER()
GLDescriptorSetLayout const* dsl = handle_cast<GLDescriptorSetLayout*>(dslh);
construct<GLDescriptorSet>(dsh, mContext, dslh, dsl);
mHandleAllocator.associateTagToHandle(dslh.getId(), std::move(tag));
}
// ------------------------------------------------------------------------------------------------
@@ -1977,7 +1948,7 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
if (UTILS_UNLIKELY(t->hwStream)) {
detachStream(t);
}
if (UTILS_UNLIKELY(t->externalTexture)) {
if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) {
mPlatform.destroyExternalImageTexture(t->externalTexture);
} else {
glDeleteTextures(1, &t->gl.id);
@@ -2117,17 +2088,13 @@ void OpenGLDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
// These are called on the application's thread
// ------------------------------------------------------------------------------------------------
Handle<HwStream> OpenGLDriver::createStreamNative(void* nativeStream, utils::CString tag) {
Handle<HwStream> OpenGLDriver::createStreamNative(void* nativeStream) {
Platform::Stream* stream = mPlatform.createStream(nativeStream);
auto handle = initHandle<GLStream>(stream);
mHandleAllocator.associateTagToHandle(handle.getId(), std::move(tag));
return handle;
return initHandle<GLStream>(stream);
}
Handle<HwStream> OpenGLDriver::createStreamAcquired(utils::CString tag) {
auto handle = initHandle<GLStream>();
mHandleAllocator.associateTagToHandle(handle.getId(), std::move(tag));
return handle;
Handle<HwStream> OpenGLDriver::createStreamAcquired() {
return initHandle<GLStream>();
}
// Stashes an acquired external image and a release callback. The image is not bound to OpenGL until
@@ -2547,20 +2514,13 @@ size_t OpenGLDriver::getMaxArrayTextureLayers() {
// Swap chains
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::commit(Handle<HwSwapChain> sch) {
DEBUG_MARKER()
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
mPlatform.commit(sc->swapChain);
auto& fs = sc->frameScheduled;
if (fs.callback) {
scheduleCallback(fs.handler, [callback = std::move(fs.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback(noop);
});
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
if (UTILS_UNLIKELY(!mFrameCompleteOps.empty())) {
whenGpuCommandsComplete([ops = std::move(mFrameCompleteOps)]() {
@@ -2626,6 +2586,10 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
uint32_t index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
@@ -3753,12 +3717,9 @@ void OpenGLDriver::beginFrame(
}
}
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
FrameScheduledCallback&& callback, uint64_t /*flags*/) {
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain>, CallbackHandler*,
FrameScheduledCallback&& /*callback*/, uint64_t /*flags*/) {
DEBUG_MARKER()
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
sc->frameScheduled.handler = handler;
sc->frameScheduled.callback = std::move(callback);
}
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain>,
@@ -28,7 +28,6 @@
#include "ShaderCompilerService.h"
#include <backend/AcquiredImage.h>
#include <backend/CallbackHandler.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
@@ -100,10 +99,6 @@ public:
struct GLSwapChain : public HwSwapChain {
using HwSwapChain::HwSwapChain;
bool rec709 = false;
struct {
CallbackHandler* handler = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
};
struct GLVertexBufferInfo : public HwVertexBufferInfo {
@@ -46,6 +46,7 @@
#include <cctype>
#include <mutex>
#include <memory>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
@@ -66,9 +67,9 @@ constexpr uint32_t MAX_NUM_SYNCHRONOUS_PROGRAMS_PER_FRAME = 1;
// ------------------------------------------------------------------------------------------------
static CString to_string(bool const b) { return CString{ b ? "true" : "false" }; }
static CString to_string(int const i) { return utils::to_string(i); }
static CString to_string(float const f) { return "float(" + utils::to_string(f) + ")"; }
static std::string to_string(bool const b) { return b ? "true" : "false"; }
static std::string to_string(int const i) { return std::to_string(i); }
static std::string to_string(float const f) { return "float(" + std::to_string(f) + ")"; }
static void logCompilationError(ShaderStage shaderType, const char* name, GLuint shaderId,
Program::ShaderBlob const& sourceCode) noexcept;
@@ -695,14 +696,14 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
bool multiview, program_token_t const& token) noexcept {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
auto const appendSpecConstantString = +[](CString& s, Program::SpecializationConstant const& sc) {
s += "#define SPIRV_CROSS_CONSTANT_ID_" + utils::to_string(sc.id) + ' ';
auto const appendSpecConstantString = +[](std::string& s, Program::SpecializationConstant const& sc) {
s += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
s += std::visit([](auto&& arg) { return to_string(arg); }, sc.value);
s += '\n';
return s;
};
CString specializationConstantString;
std::string specializationConstantString;
int32_t numViews = 2;
for (auto const& sc: specializationConstants) {
appendSpecConstantString(specializationConstantString, sc);
@@ -765,10 +766,8 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
}
std::array<std::string_view, 5> sources = {
version, prolog,
{ specializationConstantString.data(), specializationConstantString.size() },
packingFunctions,
{ body.data(), body.size() - 1 } // null-terminated
version, prolog, specializationConstantString, packingFunctions,
{ body.data(), body.size() - 1 }// null-terminated
};
// Some of the sources may be zero-length. Remove them as to avoid passing lengths of
@@ -967,18 +966,16 @@ UTILS_NOINLINE
sourceCode.size() };
size_t lc = 1;
size_t start = 0;
CString line;
std::string line;
while (true) {
size_t const end = shader.find('\n', start);
if (end == std::string_view::npos) {
auto sv = shader.substr(start);
line = { sv.data(), sv.size() };
if (end == std::string::npos) {
line = shader.substr(start);
} else {
auto sv = shader.substr(start, end - start);
line = { sv.data(), sv.size() };
line = shader.substr(start, end - start);
}
LOG(ERROR) << lc++ << ": " << line.c_str();
if (end == std::string_view::npos) {
if (end == std::string::npos) {
break;
}
start = end + 1;
+12 -18
View File
@@ -24,7 +24,6 @@
#include "VulkanConstants.h"
#include "VulkanContext.h"
#include <utils/CString.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/debug.h>
@@ -58,26 +57,26 @@ VkCommandBuffer createCommandBuffer(VkDevice device, VkCommandPool pool) {
} // anonymous namespace
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
void VulkanGroupMarkers::push(CString const& marker, Timestamp start) noexcept {
void VulkanGroupMarkers::push(std::string const& marker, Timestamp start) noexcept {
mMarkers.push_back({marker,
start.time_since_epoch().count() > 0.0
? start
: std::chrono::high_resolution_clock::now()});
}
std::pair<CString, Timestamp> VulkanGroupMarkers::pop() noexcept {
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop() noexcept {
auto ret = mMarkers.back();
mMarkers.pop_back();
return ret;
}
std::pair<CString, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
auto ret = mMarkers.front();
mMarkers.pop_front();
return ret;
}
std::pair<CString, Timestamp> const& VulkanGroupMarkers::top() const {
std::pair<std::string, Timestamp> const& VulkanGroupMarkers::top() const {
assert_invariant(!empty());
return mMarkers.back();
}
@@ -212,9 +211,7 @@ VkSemaphore VulkanCommandBuffer::submit() {
FVK_LOGI << "Submitting cmdbuffer=" << mBuffer
<< " wait=(";
for (size_t s = 0, count = mWaitSemaphores.size(); s < count; ++s) {
FVK_LOGI << "\tsemaphore=" << mWaitSemaphores[s] << "|stage="
<< mWaitSemaphoreStages[s]
<< (s < mWaitSemaphores.size() - 1 ? "\n" : "");
FVK_LOGI << mWaitSemaphores[s] << " ";
}
FVK_LOGI << ") "
<< " signal=" << mSubmission
@@ -354,7 +351,7 @@ void CommandBufferPool::waitFor(VkSemaphore previousAction, VkPipelineStageFlags
}
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
CString CommandBufferPool::topMarker() const {
std::string CommandBufferPool::topMarker() const {
if (!mGroupMarkers || mGroupMarkers->empty()) {
return "";
}
@@ -365,11 +362,11 @@ void CommandBufferPool::pushMarker(char const* marker, VulkanGroupMarkers::Times
if (!mGroupMarkers) {
mGroupMarkers = std::make_unique<VulkanGroupMarkers>();
}
mGroupMarkers->push(CString{ marker }, timestamp);
mGroupMarkers->push(marker, timestamp);
getRecording().pushMarker(marker);
}
std::pair<CString, VulkanGroupMarkers::Timestamp> CommandBufferPool::popMarker() {
std::pair<std::string, VulkanGroupMarkers::Timestamp> CommandBufferPool::popMarker() {
assert_invariant(mGroupMarkers && !mGroupMarkers->empty());
auto ret = mGroupMarkers->pop();
@@ -437,13 +434,10 @@ bool VulkanCommands::flush() {
}
if (lastSubmit != VK_NULL_HANDLE) {
// Note that the stage we're waiting on is the fragment shader stage. This assumes
// that the subsequent command buffer will only depend on
// 1) fragment output of the previous command buffer
// 2) reading/writing of buffers (i.e. UBO) of the previous command buffer
// Restricting the wait stages will allow for vertex work to proceed (more overlapping
// that the subsequent command buffer will only dependent on the fragment output of the
// previous buffer, allowing for vertex work to proceed (more overlapping
// vertex/fragment work).
pool->waitFor(lastSubmit,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT);
pool->waitFor(lastSubmit, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
lastSubmit = VK_NULL_HANDLE;
}
dependency = pool->flush();
@@ -529,7 +523,7 @@ void VulkanCommands::insertEventMarker(char const* str, uint32_t len) {
}
}
CString VulkanCommands::getTopGroupMarker() const {
std::string VulkanCommands::getTopGroupMarker() const {
if (mProtectedPool) {
return mProtectedPool->topMarker();
}
+9 -9
View File
@@ -28,7 +28,6 @@
#include "vulkan/utils/StaticVector.h"
#include <utils/Condition.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Mutex.h>
@@ -36,6 +35,7 @@
#include <chrono>
#include <list>
#include <string>
#include <utility>
namespace filament::backend {
@@ -47,14 +47,14 @@ class VulkanGroupMarkers {
public:
using Timestamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
void push(utils::CString const& marker, Timestamp start = {}) noexcept;
std::pair<utils::CString, Timestamp> pop() noexcept;
std::pair<utils::CString, Timestamp> pop_bottom() noexcept;
std::pair<utils::CString, Timestamp> const& top() const;
void push(std::string const& marker, Timestamp start = {}) noexcept;
std::pair<std::string, Timestamp> pop() noexcept;
std::pair<std::string, Timestamp> pop_bottom() noexcept;
std::pair<std::string, Timestamp> const& top() const;
bool empty() const noexcept;
private:
std::list<std::pair<utils::CString, Timestamp>> mMarkers;
std::list<std::pair<std::string, Timestamp>> mMarkers;
};
#endif // FVK_DEBUG_GROUP_MARKERS
@@ -148,9 +148,9 @@ struct CommandBufferPool {
void waitFor(VkSemaphore previousAction, VkPipelineStageFlags waitStage);
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
utils::CString topMarker() const;
std::string topMarker() const;
void pushMarker(char const* marker, VulkanGroupMarkers::Timestamp timestamp);
std::pair<utils::CString, VulkanGroupMarkers::Timestamp> popMarker();
std::pair<std::string, VulkanGroupMarkers::Timestamp> popMarker();
void insertEvent(char const* marker);
#endif
@@ -249,7 +249,7 @@ public:
void pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp = {});
void popGroupMarker();
void insertEventMarker(char const* string, uint32_t len);
utils::CString getTopGroupMarker() const;
std::string getTopGroupMarker() const;
#endif
private:
+34 -55
View File
@@ -416,8 +416,6 @@ void VulkanDriver::beginFrame(int64_t monotonic_clock_ns,
void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
FrameScheduledCallback&& callback, uint64_t flags) {
auto swapChain = resource_ptr<VulkanSwapChain>::cast(&mResourceManager, sch);
swapChain->setFrameScheduledCallback(handler, std::move(callback));
}
void VulkanDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
@@ -483,13 +481,12 @@ void VulkanDriver::finish(int dummy) {
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString tag) {
PrimitiveType pt) {
FVK_SYSTRACE_SCOPE();
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
auto ptr = resource_ptr<VulkanRenderPrimitive>::make(&mResourceManager, rph, pt, vb, ib);
ptr.inc();
mResourceManager.associateHandle(rph.getId(), std::move(tag));
}
void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
@@ -502,12 +499,11 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
}
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes, utils::CString tag) {
uint8_t attributeCount, AttributeArray attributes) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
attributeCount, attributes);
vbi.inc();
mResourceManager.associateHandle(vbih.getId(), std::move(tag));
}
void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
@@ -520,13 +516,12 @@ void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
}
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih, utils::CString tag) {
Handle<HwVertexBufferInfo> vbih) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
vertexCount, vbi);
vb.inc();
mResourceManager.associateHandle(vbh.getId(), std::move(tag));
}
void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
@@ -539,13 +534,12 @@ void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
}
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, utils::CString tag) {
uint32_t indexCount, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto elementSize = (uint8_t) getElementTypeSize(elementType);
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mContext, mAllocator,
mStagePool, mBufferCache, elementSize, indexCount);
ib.inc();
mResourceManager.associateHandle(ibh.getId(), std::move(tag));
}
void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
@@ -558,12 +552,11 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
BufferObjectBinding bindingType, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mContext, mAllocator,
mStagePool, mBufferCache, byteCount, bindingType);
bo.inc();
mResourceManager.associateHandle(boh.getId(), std::move(tag));
}
void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
@@ -577,7 +570,7 @@ void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, utils::CString tag) {
TextureUsage usage) {
FVK_SYSTRACE_SCOPE();
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mResourceManager, &mCommands,
@@ -590,34 +583,31 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
texture->transitionLayout(&commandsBuf, primaryViewRange, defaultLayout);
texture.inc();
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
uint8_t baseLevel, uint8_t levelCount) {
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, baseLevel,
levelCount);
texture.inc();
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, utils::CString tag) {
TextureSwizzle const swizzleArray[] = { r, g, b, a };
VkComponentMapping const swizzle = fvkutils::getSwizzleMap(swizzleArray);
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle);
texture.inc();
mResourceManager.associateHandle(th.getId(), std::move(tag));
backend::TextureSwizzle a) {
TextureSwizzle const swizzleArray[] = {r, g, b, a};
VkComponentMapping const swizzle = fvkutils::getSwizzleMap(swizzleArray);
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle);
texture.inc();
}
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef externalImage, utils::CString tag) {
Platform::ExternalImageHandleRef externalImage) {
FVK_SYSTRACE_SCOPE();
auto metadata = mPlatform->extractExternalImageMetadata(externalImage);
@@ -663,12 +653,11 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
}
texture.inc();
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* externalImage, utils::CString tag) {
void* externalImage) {
FVK_SYSTRACE_SCOPE();
assert_invariant(false && "Not supported in Vulkan backend");
// not supported in this backend
@@ -676,17 +665,16 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane, utils::CString tag) {
void* image, uint32_t plane) {
assert_invariant(false && "Not supported in Vulkan backend");
}
void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, utils::CString tag) {
TextureUsage usage) {
// not supported in this backend
assert_invariant(false && "Not supported in Vulkan backend");
mResourceManager.associateHandle(th.getId(), std::move(tag));
}
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
@@ -699,12 +687,11 @@ void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
mExternalImageManager.removeExternallySampledTexture(texture);
}
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::CString tag) {
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
FVK_SYSTRACE_SCOPE();
auto vprogram = resource_ptr<VulkanProgram>::make(&mResourceManager, ph, mPlatform->getDevice(),
program);
vprogram.inc();
mResourceManager.associateHandle(ph.getId(), std::move(tag));
}
void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
@@ -715,20 +702,18 @@ void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
vprogram.dec();
}
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString tag) {
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
std::move(std::move(*mDefaultRenderTarget.get())));
mDefaultRenderTarget = renderTarget;
mResourceManager.associateHandle(rth.getId(), std::move(tag));
}
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples,
uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil,
utils::CString tag) {
uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) {
FVK_SYSTRACE_SCOPE();
@@ -789,8 +774,6 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
mPlatform->getPhysicalDevice(), mContext, &mResourceManager, mAllocator, &mCommands,
width, height, samples, colorTargets, depthStencil, mStagePool, layerCount);
rt.inc();
mResourceManager.associateHandle(rth.getId(), std::move(tag));
}
void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
@@ -807,7 +790,7 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
}
}
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
VulkanCommandBuffer* cmdbuf;
if (mCurrentRenderPass.commandBuffer) {
cmdbuf = mCurrentRenderPass.commandBuffer;
@@ -819,11 +802,9 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
// buffer.
auto fence = resource_ptr<VulkanFence>::cast(&mResourceManager, fh);
fence->fence = cmdbuf->getFenceStatus();
mResourceManager.associateHandle(fh.getId(), std::move(tag));
}
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
utils::CString tag) {
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
FVK_SYSTRACE_SCOPE();
// Running gc() to guard against an edge case where the old swapchains need to have been
// destroyed before the new swapchain can be created. Otherwise, we would fail
@@ -842,11 +823,10 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
auto swapChain = resource_ptr<VulkanSwapChain>::make(&mResourceManager, sch, mPlatform,
mContext, &mResourceManager, mAllocator, &mCommands, mStagePool, nativeWindow, flags);
swapChain.inc();
mResourceManager.associateHandle(sch.getId(), std::move(tag));
}
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags, utils::CString tag) {
uint32_t height, uint64_t flags) {
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
@@ -856,24 +836,21 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
mContext, &mResourceManager, mAllocator, &mCommands, mStagePool, nullptr, flags,
VkExtent2D{width, height});
swapChain.inc();
mResourceManager.associateHandle(sch.getId(), std::move(tag));
}
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
// nothing to do, timer query was constructed in createTimerQueryS
mResourceManager.associateHandle(tqh.getId(), std::move(tag));
}
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
backend::DescriptorSetLayout&& info, utils::CString tag) {
backend::DescriptorSetLayout&& info) {
FVK_SYSTRACE_SCOPE();
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
layout.inc();
mResourceManager.associateHandle(dslh.getId(), std::move(tag));
}
void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh, utils::CString tag) {
Handle<HwDescriptorSetLayout> dslh) {
FVK_SYSTRACE_SCOPE();
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
@@ -883,8 +860,6 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
if (layout->hasExternalSamplers()) {
mAppState.hasExternalSamplerLayouts = true;
}
mResourceManager.associateHandle(dsh.getId(), std::move(tag));
}
Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept {
@@ -1015,11 +990,11 @@ void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
}
}
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream, utils::CString tag) {
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream) {
return {};
}
Handle<HwStream> VulkanDriver::createStreamAcquired(utils::CString tag) {
Handle<HwStream> VulkanDriver::createStreamAcquired() {
return {};
}
@@ -1632,7 +1607,7 @@ void VulkanDriver::commit(Handle<HwSwapChain> sch) {
auto swapChain = resource_ptr<VulkanSwapChain>::cast(&mResourceManager, sch);
// Present the backbuffer after the most recent command buffer submission has finished.
swapChain->present(*this);
swapChain->present();
}
void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
@@ -2104,6 +2079,10 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
void VulkanDriver::resetState(int) {
}
void VulkanDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mResourceManager.associateHandle(handleId, std::move(tag));
}
void VulkanDriver::endCommandRecording() {
mCommands.flush();
mPipelineCache.resetBoundPipeline();
@@ -32,7 +32,6 @@
#include <utils/compiler.h> // UTILS_FALLTHROUGH
#include <utils/Panic.h> // ASSERT_POSTCONDITION
#include <utils/CString.h>
using namespace bluevk;
@@ -286,7 +285,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
<< " error=" << static_cast<int32_t>(result);
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
utils::CString name{ builder.getName().c_str(), builder.getName().size() };
std::string name{ builder.getName().c_str(), builder.getName().size() };
switch (static_cast<ShaderStage>(i)) {
case ShaderStage::VERTEX:
name += "_vs";
+1 -6
View File
@@ -308,10 +308,7 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
// Creates a special "default" render target (i.e. associated with the swap chain)
explicit VulkanRenderTarget();
VulkanRenderTarget(VulkanRenderTarget&& target)
: HwRenderTarget(0, 0),
mOffscreen(false),
mProtected(false) {
VulkanRenderTarget(VulkanRenderTarget&& target) {
swap(std::move(target));
}
@@ -368,8 +365,6 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
private:
void swap(VulkanRenderTarget&& target) {
std::swap(width, target.width);
std::swap(height, target.height);
std::swap(mOffscreen, target.mOffscreen);
std::swap(mProtected, target.mProtected);
std::swap(mInfo, target.mInfo);
@@ -93,7 +93,7 @@ void VulkanSwapChain::update() {
mLayerCount = bundle.layerCount;
}
void VulkanSwapChain::present(DriverBase& driver) {
void VulkanSwapChain::present() {
if (!mHeadless && mTransitionSwapChainImageLayoutForPresent) {
VulkanCommandBuffer& commands = mCommands->get();
VkImageSubresourceRange const subresources{
@@ -120,14 +120,6 @@ void VulkanSwapChain::present(DriverBase& driver) {
// We presented the last acquired buffer.
mAcquired = false;
mIsFirstRenderPass = true;
if (frameScheduled.callback) {
driver.scheduleCallback(frameScheduled.handler,
[callback = std::move(frameScheduled.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback(noop);
});
}
}
void VulkanSwapChain::acquire(bool& resized) {
+1 -14
View File
@@ -47,7 +47,7 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
~VulkanSwapChain();
void present(DriverBase& driver);
void present();
// Acquire a new image from the swapchain. If the image is not available it would wait until it
// is.
@@ -79,13 +79,6 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
inline bool isProtected() noexcept {
return mPlatform->isProtected(swapChain);
}
inline void setFrameScheduledCallback(CallbackHandler* handler,
FrameScheduledCallback&& callback) noexcept {
frameScheduled.handler = handler;
frameScheduled.callback = std::move(callback);
}
private:
static constexpr int IMAGE_READY_SEMAPHORE_COUNT = FVK_MAX_COMMAND_BUFFERS;
@@ -101,12 +94,6 @@ private:
bool const mFlushAndWaitOnResize;
bool const mTransitionSwapChainImageLayoutForPresent;
// These fields store a callback to notify the client that Filament is commiting a frame.
struct {
CallbackHandler* handler = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
// transitions, which are useful here.
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
@@ -106,7 +106,7 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
return { vals[0], vals[1], vals[2], vals[3] };
};
// We make sure all identities are mapped into respective channels so that actual channel
// We make sure all all identities are mapped into respective channels so that actual channel
// mapping will be passed onto the output.
VkComponentMapping const prevExplicit = identityToChannel(prev);
VkComponentMapping const nextExplicit = identityToChannel(next);
@@ -95,7 +95,7 @@ ResourceType getTypeEnum() noexcept {
return ResourceType::UNDEFINED_TYPE;
}
std::string_view getTypeStr(ResourceType type) {
std::string getTypeStr(ResourceType type) {
switch (type) {
case ResourceType::BUFFER_OBJECT:
return "BufferObject";
@@ -58,7 +58,7 @@ enum class ResourceType : uint8_t {
template<typename D>
ResourceType getTypeEnum() noexcept;
std::string_view getTypeStr(ResourceType type);
std::string getTypeStr(ResourceType type);
inline bool isThreadSafeType(ResourceType type) {
return type == ResourceType::FENCE || type == ResourceType::TIMER_QUERY;
File diff suppressed because it is too large Load Diff
+45 -65
View File
@@ -154,8 +154,7 @@ void WebGPUDriver::beginFrame(int64_t monotonic_clock_ns,
void WebGPUDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
CallbackHandler* handler, FrameScheduledCallback&& callback, uint64_t flags) {
auto swapChain = handleCast<WebGPUSwapChain>(sch);
swapChain->setFrameScheduledCallback(handler, std::move(callback));
}
void WebGPUDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
@@ -208,17 +207,7 @@ void WebGPUDriver::finish(int /* dummy */) {
FWGPU_SYSTRACE_SCOPE();
mDevice.Tick();
mAdapter.GetInstance().ProcessEvents();
mReadPixelMapsCounter.waitForAllToFinish();
flush();
// Some applications/samples might call finish in the very beginning of an application before
// creating any resources/tasks to flush out the system on any pending work from previous runs.
// Currently, gltf_viewer sample on android exhibit this behavior.
// Bail out early to safeguard against those cases. Otherwise, OnSubmittedWorkDone will
// hang on work that was never submitted.
if (mCommandEncoder == nullptr) {
return;
}
// Wait for all previously submitted work to finish.
std::mutex syncPoint;
std::condition_variable syncCondition;
@@ -236,6 +225,7 @@ void WebGPUDriver::finish(int /* dummy */) {
});
std::unique_lock<std::mutex> lock(syncPoint);
syncCondition.wait(lock, [&done] { return done; });
mReadPixelMapsCounter.waitForAllToFinish();
}
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
@@ -445,7 +435,7 @@ Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
// ------------------------------------------------------------------------------------------------
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
const uint64_t flags, utils::CString tag) {
const uint64_t flags) {
FWGPU_SYSTRACE_SCOPE();
mNativeWindow = nativeWindow;
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
@@ -467,12 +457,10 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
if (mDefaultRenderTarget) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
setDebugTag(sch.getId(), std::move(tag));
}
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags, utils::CString tag) {
uint32_t height, uint64_t flags) {
wgpu::Extent2D extent = { .width = width, .height = height };
mSwapChain = constructHandle<WebGPUSwapChain>(sch, extent, mAdapter,
mDevice, flags);
@@ -480,69 +468,56 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
if (mDefaultRenderTarget) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
setDebugTag(sch.getId(), std::move(tag));
}
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vertexBufferInfoHandle,
const uint8_t bufferCount, const uint8_t attributeCount, const AttributeArray attributes,
utils::CString tag) {
const uint8_t bufferCount, const uint8_t attributeCount, const AttributeArray attributes) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUVertexBufferInfo>(vertexBufferInfoHandle, bufferCount, attributeCount,
attributes, mDeviceLimits);
setDebugTag(vertexBufferInfoHandle.getId(), std::move(tag));
}
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vertexBufferHandle,
const uint32_t vertexCount, Handle<HwVertexBufferInfo> vertexBufferInfoHandle,
utils::CString tag) {
const uint32_t vertexCount, Handle<HwVertexBufferInfo> vertexBufferInfoHandle) {
FWGPU_SYSTRACE_SCOPE();
const auto vertexBufferInfo = handleCast<WebGPUVertexBufferInfo>(vertexBufferInfoHandle);
constructHandle<WebGPUVertexBuffer>(vertexBufferHandle, vertexCount,
vertexBufferInfo->bufferCount, vertexBufferInfoHandle);
setDebugTag(vertexBufferHandle.getId(), std::move(tag));
}
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> indexBufferHandle,
const ElementType elementType, const uint32_t indexCount, const BufferUsage usage,
utils::CString tag) {
const ElementType elementType, const uint32_t indexCount, const BufferUsage usage) {
FWGPU_SYSTRACE_SCOPE();
const auto elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
constructHandle<WebGPUIndexBuffer>(indexBufferHandle, mDevice, elementSize, indexCount);
setDebugTag(indexBufferHandle.getId(), std::move(tag));
}
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> bufferObjectHandle,
const uint32_t byteCount, const BufferObjectBinding bindingType, const BufferUsage usage,
utils::CString tag) {
const uint32_t byteCount, const BufferObjectBinding bindingType, const BufferUsage usage) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUBufferObject>(bufferObjectHandle, mDevice, bindingType, byteCount);
setDebugTag(bufferObjectHandle.getId(), std::move(tag));
}
void WebGPUDriver::createTextureR(Handle<HwTexture> textureHandle, const SamplerType target,
const uint8_t levels, const TextureFormat format, const uint8_t samples,
const uint32_t width, const uint32_t height, const uint32_t depth,
const TextureUsage usage, utils::CString tag) {
const TextureUsage usage) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUTexture>(textureHandle, target, levels, format, samples, width, height,
depth, usage, mDevice);
setDebugTag(textureHandle.getId(), std::move(tag));
}
void WebGPUDriver::createTextureViewR(Handle<HwTexture> textureHandle,
Handle<HwTexture> sourceTextureHandle, const uint8_t baseLevel, const uint8_t levelCount,
utils::CString tag) {
Handle<HwTexture> sourceTextureHandle, const uint8_t baseLevel, const uint8_t levelCount) {
auto source = handleCast<WebGPUTexture>(sourceTextureHandle);
constructHandle<WebGPUTexture>(textureHandle, source, baseLevel, levelCount);
setDebugTag(textureHandle.getId(), std::move(tag));
}
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> textureHandle,
Handle<HwTexture> sourceTextureHandle, const backend::TextureSwizzle r,
const backend::TextureSwizzle g, const backend::TextureSwizzle b,
const backend::TextureSwizzle a, utils::CString tag) {
const backend::TextureSwizzle a) {
if (!isTextureSwizzleSupported()) {
FWGPU_LOGW << "WebGPUDriver::createTextureViewSwizzleR called while texture swizzling is "
@@ -552,24 +527,37 @@ void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> textureHandle,
auto sourceTexture{ handleCast<WebGPUTexture>(sourceTextureHandle) };
assert_invariant(sourceTexture);
wgpu::TextureComponentSwizzle const nextSwizzle{
wgpu::TextureComponentSwizzle swizzle
{
.r = toWGPUComponentSwizzle(r),
.g = toWGPUComponentSwizzle(g),
.b = toWGPUComponentSwizzle(b),
.a = toWGPUComponentSwizzle(a),
};
// The WebGPUTexture constructor for swizzled views will handle composing the swizzle and
// creating the new texture view.
constructHandle<WebGPUTexture>(textureHandle, sourceTexture, nextSwizzle);
wgpu::TextureComponentSwizzleDescriptor swizzleDesc {};
swizzleDesc.swizzle = swizzle;
setDebugTag(textureHandle.getId(), std::move(tag));
const wgpu::TextureViewDescriptor viewDesc {
.nextInChain = &swizzleDesc,
.label = "swizzled_texture_view",
.format = sourceTexture->getTexture().GetFormat(),
.dimension = sourceTexture->getViewDimension(),
.baseMipLevel = 0,
.mipLevelCount = sourceTexture->getTexture().GetMipLevelCount(),
.baseArrayLayer = 0,
.arrayLayerCount = sourceTexture->getTexture().GetDepthOrArrayLayers(),
};
wgpu::TextureView swizzledView{ sourceTexture->getTexture().CreateView(&viewDesc) };
FILAMENT_CHECK_POSTCONDITION(swizzledView) << "Failed to create swizzled Texture view";
constructHandle<WebGPUTexture>(textureHandle, sourceTexture, swizzledView);
}
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> textureHandle,
const backend::SamplerType target, const backend::TextureFormat format,
const uint32_t width, const uint32_t height, const backend::TextureUsage usage,
Platform::ExternalImageHandleRef externalImage, utils::CString tag) {
Platform::ExternalImageHandleRef externalImage) {
FWGPU_SYSTRACE_SCOPE();
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
@@ -577,27 +565,27 @@ void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> textureHandle,
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> textureHandle,
const backend::SamplerType target, const backend::TextureFormat format,
const uint32_t width, const uint32_t height, const backend::TextureUsage usage,
void* externalImage, utils::CString tag) {
void* externalImage) {
FWGPU_SYSTRACE_SCOPE();
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> textureHandle,
const backend::TextureFormat format, const uint32_t width, const uint32_t height,
const backend::TextureUsage usage, void* image, const uint32_t plane, utils::CString tag) {
const backend::TextureUsage usage, void* image, const uint32_t plane) {
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
void WebGPUDriver::importTextureR(Handle<HwTexture> textureHandle, const intptr_t id,
const SamplerType target, const uint8_t levels, const TextureFormat format,
const uint8_t samples, const uint32_t width, const uint32_t height, const uint32_t depth,
const TextureUsage usage, utils::CString tag) {
const TextureUsage usage) {
PANIC_POSTCONDITION("Import WebGPU Texture is not supported");
}
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> renderPrimitiveHandle,
Handle<HwVertexBuffer> vertexBufferHandle, Handle<HwIndexBuffer> indexBufferHandle,
const PrimitiveType primitiveType, utils::CString tag) {
const PrimitiveType primitiveType) {
FWGPU_SYSTRACE_SCOPE();
assert_invariant(mDevice);
const auto renderPrimitive = constructHandle<WebGPURenderPrimitive>(renderPrimitiveHandle);
@@ -606,31 +594,27 @@ void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> renderPrimit
renderPrimitive->vertexBuffer = vertexBuffer;
renderPrimitive->indexBuffer = indexBuffer;
renderPrimitive->type = primitiveType;
setDebugTag(renderPrimitiveHandle.getId(), std::move(tag));
}
void WebGPUDriver::createProgramR(Handle<HwProgram> programHandle, Program&& program,
utils::CString tag) {
void WebGPUDriver::createProgramR(Handle<HwProgram> programHandle, Program&& program) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUProgram>(programHandle, mDevice, program);
setDebugTag(programHandle.getId(), std::move(tag));
}
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> renderTargetHandle,
utils::CString tag) {
const int /* dummy */) {
assert_invariant(!mDefaultRenderTarget);
mDefaultRenderTarget = constructHandle<WebGPURenderTarget>(renderTargetHandle);
assert_invariant(mDefaultRenderTarget);
if (mSwapChain) {
setDefaultTargetFlags(*mDefaultRenderTarget, *mSwapChain);
}
setDebugTag(renderTargetHandle.getId(), std::move(tag));
}
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> renderTargetHandle,
const TargetBufferFlags targetFlags, const uint32_t width, const uint32_t height,
const uint8_t samples, const uint8_t layerCount, const MRT color,
const TargetBufferInfo depth, const TargetBufferInfo stencil, utils::CString tag) {
const TargetBufferInfo depth, const TargetBufferInfo stencil) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPURenderTarget>(
renderTargetHandle, width, height, samples, layerCount, color, depth, stencil,
@@ -639,43 +623,39 @@ void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> renderTargetHandle
return handleCast<WebGPUTexture>(textureHandle);
},
mDevice);
setDebugTag(renderTargetHandle.getId(), std::move(tag));
}
void WebGPUDriver::createFenceR(Handle<HwFence> fenceHandle, utils::CString tag) {
void WebGPUDriver::createFenceR(Handle<HwFence> fenceHandle, const int /* dummy */) {
// The handle is constructed synchronously in createFenceS.
const auto fence = handleCast<WebGPUFence>(fenceHandle);
assert_invariant(mQueue);
fence->addMarkerToQueueState(mQueue);
setDebugTag(fenceHandle.getId(), std::move(tag));
}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
void WebGPUDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle,
backend::DescriptorSetLayout&& info, utils::CString tag) {
backend::DescriptorSetLayout&& info) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUDescriptorSetLayout>(descriptorSetLayoutHandle, std::move(info), mDevice);
setDebugTag(descriptorSetLayoutHandle.getId(), std::move(tag));
}
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> descriptorSetHandle,
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle, utils::CString tag) {
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle) {
FWGPU_SYSTRACE_SCOPE();
auto layout = handleCast<WebGPUDescriptorSetLayout>(descriptorSetLayoutHandle);
constructHandle<WebGPUDescriptorSet>(descriptorSetHandle, layout->getLayout(),
layout->getBindGroupEntries());
setDebugTag(descriptorSetHandle.getId(), std::move(tag));
}
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream, utils::CString tag) {
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
return {
//todo
};
}
Handle<HwStream> WebGPUDriver::createStreamAcquired(utils::CString tag) {
Handle<HwStream> WebGPUDriver::createStreamAcquired() {
return {
//todo
};
@@ -1373,7 +1353,7 @@ void WebGPUDriver::commit(Handle<HwSwapChain> swapChainHandle) {
if (UTILS_VERY_UNLIKELY(!mCommandEncoder)) {
// nothing to submit
if (UTILS_LIKELY(mSwapChain)) {
mSwapChain->present(*this);
mSwapChain->present();
}
return;
}
@@ -1407,7 +1387,7 @@ void WebGPUDriver::commit(Handle<HwSwapChain> swapChainHandle) {
}
mTextureView = nullptr;
assert_invariant(mSwapChain);
mSwapChain->present(*this);
mSwapChain->present();
}
void WebGPUDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
@@ -68,7 +68,6 @@ private:
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
void setDebugTag(HandleBase::HandleId handleId, utils::CString tag);
// The platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
// handled in the WebGPUPlatform.
@@ -293,11 +293,10 @@ wgpu::RenderPipeline WebGPUPipelineCache::createRenderPipeline(
},
.primitive = {
.topology = toWebGPU(request.primitiveType),
// TODO This won't always be the case for the primitives bound. But this particular field
// in the pipeline struct is only meant for restarting the strip, which we don't need so far.
.stripIndexFormat =
isStripPrimitiveType(request.primitiveType)? wgpu::IndexFormat::Uint16 :
wgpu::IndexFormat::Undefined,
// TODO should we assume some constant format here or is there a way to get
// this from PipelineState somehow or elsewhere?
// Perhaps, cache/assert format from index buffers as they are requested?
.stripIndexFormat = wgpu::IndexFormat::Undefined,
.frontFace = request.rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
.cullMode = toWebGPU(request.rasterState.culling),
// TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
@@ -313,10 +312,12 @@ wgpu::RenderPipeline WebGPUPipelineCache::createRenderPipeline(
},
.fragment = nullptr // will add below if fragment module is included
};
FILAMENT_CHECK_POSTCONDITION(!isStripPrimitiveType(request.primitiveType) ||
pipelineDescriptor.primitive.stripIndexFormat != wgpu::IndexFormat::Undefined)
<< "If the topology is a strip format, e.g. TriangleStrip, the stripIndexFormat cannot "
"be Undefined.";
// TODO:
if (pipelineDescriptor.primitive.topology == wgpu::PrimitiveTopology::LineStrip ||
pipelineDescriptor.primitive.topology == wgpu::PrimitiveTopology::TriangleStrip) {
PANIC_POSTCONDITION("stripIndexFormat must be set for strip topologies. "
"This needs to be plumbed through from the RenderPrimitive.");
}
wgpu::FragmentState fragmentState = {};
const wgpu::BlendState blendState {
@@ -161,7 +161,7 @@ private:
// render targets... //
uint8_t multisampleCount{ 0 }; // 1 : 313
uint8_t colorFormatCount{ 0 }; // 1 : 314
uint8_t padding[5]{ 0 }; // 5 : 315
uint8_t padding[5]{ 0 }; // 5 : 319
TargetBufferFlags targetRenderFlags{ TargetBufferFlags::NONE }; // 4 : 320
wgpu::TextureFormat depthStencilFormat { wgpu::TextureFormat::Undefined }; // 4 : 324
wgpu::TextureFormat colorFormats[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]{ //
@@ -386,17 +386,10 @@ wgpu::Texture WebGPUSwapChain::getCurrentTexture() {
}
void WebGPUSwapChain::present(DriverBase& driver) {
void WebGPUSwapChain::present() {
if (!isHeadless()) {
mSurface.Present();
}
if (frameScheduled.callback) {
driver.scheduleCallback(frameScheduled.handler,
[callback = std::move(frameScheduled.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback(noop);
});
}
}
}// namespace filament::backend
+1 -11
View File
@@ -49,12 +49,7 @@ public:
[[nodiscard]] bool isHeadless() const { return mType == SwapChainType::HEADLESS; }
void present(DriverBase& driver);
void setFrameScheduledCallback(CallbackHandler* handler, FrameScheduledCallback&& callback) {
frameScheduled.handler = handler;
frameScheduled.callback = std::move(callback);
}
void present();
private:
@@ -80,11 +75,6 @@ private:
uint8_t mHeadlessBufferIndex = 0;
std::array<wgpu::Texture, mHeadlessBufferCount> mRenderTargetTextures;
std::array<wgpu::TextureView, mHeadlessBufferCount> mRenderTargetViews;
struct {
CallbackHandler* handler = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
};
} // namespace filament::backend
+18 -44
View File
@@ -216,9 +216,7 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
mBlockWidth{ filament::backend::getBlockWidth(format) },
mBlockHeight{ filament::backend::getBlockHeight(format) },
mDefaultMipLevel{ 0 },
mDefaultBaseArrayLayer{ 0 },
// an undefined mSwizzle means that is not a swizzle view
mSwizzle{} {
mDefaultBaseArrayLayer{ 0 } {
assert_invariant(
samples == 1 ||
samples == 4 &&
@@ -281,36 +279,11 @@ WebGPUTexture::WebGPUTexture(WebGPUTexture const* src, const uint8_t baseLevel,
mTexture{ src->mTexture },
mDefaultMipLevel{ baseLevel },
mDefaultBaseArrayLayer{ src->mArrayLayerCount },
mMsaaSidecarTexture{ src->mMsaaSidecarTexture },
mSwizzle{ src->mSwizzle } {
const bool swizzleUndefined{ (src->mSwizzle.r == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.g == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.b == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.a == wgpu::ComponentSwizzle::Undefined) };
if (swizzleUndefined) {
mDefaultTextureView = makeTextureView(mDefaultMipLevel, levelCount, 0,
mDefaultBaseArrayLayer, src->getViewDimension());
} else {
wgpu::TextureComponentSwizzleDescriptor swizzleDesc{};
swizzleDesc.swizzle = mSwizzle;
const wgpu::TextureViewDescriptor viewDesc{
.nextInChain = &swizzleDesc,
.label = "swizzled_texture_view",
.format = mTexture.GetFormat(),
.dimension = src->getViewDimension(),
.baseMipLevel = mDefaultMipLevel,
.mipLevelCount = levelCount,
.baseArrayLayer = 0,
.arrayLayerCount = mDefaultBaseArrayLayer,
};
mDefaultTextureView = mTexture.CreateView(&viewDesc);
FILAMENT_CHECK_POSTCONDITION(mDefaultTextureView)
<< "Failed to create swizzled Texture view";
}
}
mDefaultTextureView{ makeTextureView(mDefaultMipLevel, levelCount, 0, mDefaultBaseArrayLayer,
toWebGPUTextureViewDimension(src->target)) },
mMsaaSidecarTexture{ src->mMsaaSidecarTexture } {}
WebGPUTexture::WebGPUTexture(const WebGPUTexture* src,
const wgpu::TextureComponentSwizzle nextSwizzle) noexcept
WebGPUTexture::WebGPUTexture(const WebGPUTexture* src, const wgpu::TextureView view) noexcept
: HwTexture{ src->target, src->levels, src->samples, src->width, src->height, src->depth,
src->format, src->usage},
mViewFormat{ src->mViewFormat },
@@ -325,19 +298,20 @@ WebGPUTexture::WebGPUTexture(const WebGPUTexture* src,
mTexture{ src->mTexture },
mDefaultMipLevel{ src->mDefaultMipLevel },
mDefaultBaseArrayLayer{ 0 },
mMsaaSidecarTexture{src->mMsaaSidecarTexture},
mSwizzle{ composeSwizzle(src->getSwizzle(), nextSwizzle) } {
wgpu::TextureComponentSwizzleDescriptor swizzleDesc{};
swizzleDesc.swizzle = mSwizzle;
mDefaultTextureView{ view },
mMsaaSidecarTexture{src->mMsaaSidecarTexture}{}
const wgpu::TextureViewDescriptor viewDesc{
.nextInChain = &swizzleDesc,
.label = "swizzled_texture_view",
.format = mTexture.GetFormat(),
.dimension = src->getViewDimension(),
};
mDefaultTextureView = mTexture.CreateView(&viewDesc);
FILAMENT_CHECK_POSTCONDITION(mDefaultTextureView) << "Failed to create swizzled Texture view";
wgpu::Texture const& WebGPUTexture::getMsaaSidecarTexture(const uint8_t sampleCount) const {
if (mMsaaSidecarTexture == nullptr) {
return mMsaaSidecarTexture; // nullptr (no such sidecar)
}
FILAMENT_CHECK_PRECONDITION(sampleCount == mMsaaSidecarTexture.GetSampleCount())
<< "The MSAA sidecar texture has a different sample count ("
<< mMsaaSidecarTexture.GetSampleCount() << ") than requested (" << +sampleCount
<< "). Note that this restriction was written when WebGPU only supported msaa "
"textures with 4 samples. If that has changed, this implementation should be "
"updated (e.g. map of sidecar textures by sampleCount or something).";
return mMsaaSidecarTexture;
}
bool WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(const wgpu::TextureFormat format) {
+13 -8
View File
@@ -47,11 +47,12 @@ public:
WebGPUTexture(WebGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
/**
* @param nextSwizzle the swizzle to apply to the source texture.
* Creates a new texture view by composing the nextSwizzle with the source which itself it
* could be a swizzled view
* @param textureView texture view to use for the respective texture. e.g. it can be a
* swizzled Texture view for that filament texture
*
* Associates the underlying texture with the given texture view
*/
WebGPUTexture(WebGPUTexture const* source, wgpu::TextureComponentSwizzle nextSwizzle) noexcept;
WebGPUTexture(WebGPUTexture const* source, wgpu::TextureView textureView) noexcept;
[[nodiscard]] wgpu::TextureAspect getAspect() const { return mAspect; }
@@ -61,6 +62,8 @@ public:
[[nodiscard]] wgpu::Texture const& getTexture() const { return mTexture; }
[[nodiscard]] wgpu::Texture const& getMsaaSidecarTexture(uint8_t sampleCount) const;
[[nodiscard]] wgpu::TextureView const& getDefaultTextureView() const {
return mDefaultTextureView;
}
@@ -71,8 +74,6 @@ public:
[[nodiscard]] wgpu::TextureViewDimension getViewDimension() const { return mDimension; }
[[nodiscard]] wgpu::TextureFormat getViewFormat() const { return mViewFormat; }
[[nodiscard]] wgpu::TextureComponentSwizzle getSwizzle() const { return mSwizzle; }
[[nodiscard]] uint32_t getArrayLayerCount() const { return mArrayLayerCount; }
[[nodiscard]] MipmapGenerationStrategy getMipmapGenerationStrategy() const {
@@ -101,6 +102,12 @@ public:
wgpu::TextureView makeMsaaSidecarTextureViewIfTextureSidecarExists(uint8_t samples,
uint8_t mipLevel, uint32_t arrayLayer) const;
/**
* @return nullptr if a MSAA sidecar texture is not appliable, otherwise a view to one
*/
[[nodiscard]] wgpu::TextureView makeMsaaSidecarTextureView(wgpu::Texture const&,
uint8_t mipLevel, uint32_t arrayLayer) const;
/**
* @param format a required texture format (can be a view to a different underlying texture
* format)
@@ -137,8 +144,6 @@ private:
// by sampleCount or something like that.
// For now that complexity and cost is not warranted due to WebGPU's restrictions.
wgpu::Texture mMsaaSidecarTexture = nullptr;
// an undefined mSwizzle means that is not a swizzle view
wgpu::TextureComponentSwizzle mSwizzle{};
[[nodiscard]] wgpu::TextureView makeTextureView(const uint8_t& baseLevel,
const uint8_t& levelCount, const uint32_t& baseArrayLayer,
@@ -605,85 +605,6 @@ namespace filament::backend {
return retUsage;
}
/**
* "Updates" the previous swizzle parameters with the next/new parameters, essentially stacking
* swizzle parameters. Essentially this combines the parameters such that the result is
* the same mapping of channels you would get if you first applied the "previous" mapping
* followed by the "next" mapping.
*/
[[nodiscard]] constexpr wgpu::TextureComponentSwizzle composeSwizzle(
wgpu::TextureComponentSwizzle const& previous, wgpu::TextureComponentSwizzle const& next) {
// start with the "next" values...
wgpu::ComponentSwizzle result[] { next.r, next.g, next.b, next.a };
// track the current channel as we go through values to know what to assign in the undefined
// case...
wgpu::ComponentSwizzle channel{wgpu::ComponentSwizzle::R};
for (auto& out: result) {
switch (out) {
case wgpu::ComponentSwizzle::R:
if (previous.r != wgpu::ComponentSwizzle::Undefined) {
out = previous.r;
}
break;
case wgpu::ComponentSwizzle::G:
if (previous.g != wgpu::ComponentSwizzle::Undefined) {
out = previous.g;
}
break;
case wgpu::ComponentSwizzle::B:
if (previous.b != wgpu::ComponentSwizzle::Undefined) {
out = previous.b;
}
break;
case wgpu::ComponentSwizzle::A:
if (previous.a != wgpu::ComponentSwizzle::Undefined) {
out = previous.a;
}
break;
// Do not modify the (next) value for explicit One or Zero...
case wgpu::ComponentSwizzle::Zero:
case wgpu::ComponentSwizzle::One:
break;
case wgpu::ComponentSwizzle::Undefined:
// fallback to the previous value if the next value is undefined...
switch (channel) {
case wgpu::ComponentSwizzle::R:
out = previous.r;
break;
case wgpu::ComponentSwizzle::G:
out = previous.g;
break;
case wgpu::ComponentSwizzle::B:
out = previous.b;
break;
case wgpu::ComponentSwizzle::A:
out = previous.a;
break;
default:
// should not be possible...
out = wgpu::ComponentSwizzle::Undefined;
break;
}
break;
}
switch (channel) {
case wgpu::ComponentSwizzle::R:
channel = wgpu::ComponentSwizzle::G;
break;
case wgpu::ComponentSwizzle::G:
channel = wgpu::ComponentSwizzle::B;
break;
case wgpu::ComponentSwizzle::B:
channel = wgpu::ComponentSwizzle::A;
break;
default:
channel = wgpu::ComponentSwizzle::Undefined;
break;
}
}
return { .r = result[0], .g = result[1], .b = result[2], .a = result[3] };
}
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
+1 -1
View File
@@ -71,7 +71,7 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
Shader shader = createShader();
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// To test large buffers (which exercise a different code path) create an extra large
// buffer. Only the first 3 vertices will be used.
+4 -4
View File
@@ -323,7 +323,7 @@ TEST_F(LoadImageTest, UpdateImage2D) {
// Create a platform-specific SwapChain and make it current.
auto swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create a program.
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
@@ -407,7 +407,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
// Create a platform-specific SwapChain and make it current.
auto swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create a program.
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
@@ -495,7 +495,7 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
// Create a platform-specific SwapChain and make it current.
auto swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create a program.
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
@@ -575,7 +575,7 @@ TEST_F(LoadImageTest, UpdateImage3D) {
// Create a platform-specific SwapChain and make it current.
auto swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create a program.
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
+1 -1
View File
@@ -66,7 +66,7 @@ TEST_F(BackendTest, MRT) {
TrianglePrimitive triangle(api);
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
// Create two Textures.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
+1 -1
View File
@@ -154,7 +154,7 @@ TEST_F(BackendTest, TextureViewLod) {
}
backend::Handle<HwRenderTarget> defaultRenderTarget =
cleanup.add(api.createDefaultRenderTarget());
cleanup.add(api.createDefaultRenderTarget(0));
PipelineState state = getColorWritePipelineState();
texturedShader.addProgramToPipelineState(state);
@@ -75,7 +75,7 @@ TEST_F(BackendTest, MissingRequiredAttributes) {
ShaderUniformType::None),
});
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget());
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
TrianglePrimitive triangle(api);
@@ -59,7 +59,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
Shader shader = createShader(api, cleanup, sBackend);
backend::Handle<HwRenderTarget> defaultRenderTarget = cleanup.add(
api.createDefaultRenderTarget());
api.createDefaultRenderTarget(0));
// Create a texture that will be backed by an external image.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
@@ -124,7 +124,7 @@ TEST_F(BackendTest, RenderExternalImage) {
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
backend::Handle<HwRenderTarget> defaultRenderTarget = cleanup.add(
api.createDefaultRenderTarget());
api.createDefaultRenderTarget(0));
// require users to create two Filament textures and have two material parameters
// add a "plane" parameter to setExternalImage
@@ -1,171 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "webgpu/WebGPUTextureHelpers.h"
#include <gtest/gtest.h>
#include <webgpu/webgpu_cpp.h>
namespace test {
TEST(composeSwizzle, allUndefined) {
const wgpu::TextureComponentSwizzle undefinedPrevious{
.r = wgpu::ComponentSwizzle::Undefined,
.g = wgpu::ComponentSwizzle::Undefined,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::Undefined,
};
const wgpu::TextureComponentSwizzle undefinedNext{
.r = wgpu::ComponentSwizzle::Undefined,
.g = wgpu::ComponentSwizzle::Undefined,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::Undefined,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(undefinedPrevious,
undefinedNext) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::Undefined);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::Undefined);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::Undefined);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::Undefined);
}
TEST(composeSwizzle, previousUndefined) {
const wgpu::TextureComponentSwizzle undefinedPrevious{
.r = wgpu::ComponentSwizzle::Undefined,
.g = wgpu::ComponentSwizzle::Undefined,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::Undefined,
};
const wgpu::TextureComponentSwizzle definedNext{
.r = wgpu::ComponentSwizzle::G,
.g = wgpu::ComponentSwizzle::R,
.b = wgpu::ComponentSwizzle::A,
.a = wgpu::ComponentSwizzle::B,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(undefinedPrevious,
definedNext) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::G);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::R);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::A);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::B);
}
TEST(composeSwizzle, nextUndefined) {
const wgpu::TextureComponentSwizzle definedPrevious{
.r = wgpu::ComponentSwizzle::G,
.g = wgpu::ComponentSwizzle::R,
.b = wgpu::ComponentSwizzle::A,
.a = wgpu::ComponentSwizzle::B,
};
const wgpu::TextureComponentSwizzle undefinedNext{
.r = wgpu::ComponentSwizzle::Undefined,
.g = wgpu::ComponentSwizzle::Undefined,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::Undefined,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(definedPrevious,
undefinedNext) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::G);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::R);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::A);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::B);
}
TEST(composeSwizzle, bothDefinedNoSwizzling) {
const wgpu::TextureComponentSwizzle previousOneToOneMapping{
.r = wgpu::ComponentSwizzle::R,
.g = wgpu::ComponentSwizzle::G,
.b = wgpu::ComponentSwizzle::B,
.a = wgpu::ComponentSwizzle::A,
};
const wgpu::TextureComponentSwizzle nextOneToOneMapping{
.r = wgpu::ComponentSwizzle::R,
.g = wgpu::ComponentSwizzle::G,
.b = wgpu::ComponentSwizzle::B,
.a = wgpu::ComponentSwizzle::A,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(
previousOneToOneMapping, nextOneToOneMapping) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::R);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::G);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::B);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::A);
}
TEST(composeSwizzle, bothDefined) {
const wgpu::TextureComponentSwizzle previous{
.r = wgpu::ComponentSwizzle::G,
.g = wgpu::ComponentSwizzle::R,
.b = wgpu::ComponentSwizzle::A,
.a = wgpu::ComponentSwizzle::B,
};
const wgpu::TextureComponentSwizzle next{
.r = wgpu::ComponentSwizzle::A,
.g = wgpu::ComponentSwizzle::B,
.b = wgpu::ComponentSwizzle::G,
.a = wgpu::ComponentSwizzle::R,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(previous,
next) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::B);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::A);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::R);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::G);
}
TEST(composeSwizzle, bothPartiallyDefined) {
const wgpu::TextureComponentSwizzle partiallyDefinedPrevious{
.r = wgpu::ComponentSwizzle::Undefined,
.g = wgpu::ComponentSwizzle::B,
.b = wgpu::ComponentSwizzle::G,
.a = wgpu::ComponentSwizzle::Undefined,
};
const wgpu::TextureComponentSwizzle partiallyDefinedNext{
.r = wgpu::ComponentSwizzle::A,
.g = wgpu::ComponentSwizzle::G,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::R,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(
partiallyDefinedPrevious, partiallyDefinedNext) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::A);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::B);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::G);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::R);
}
TEST(composeSwizzle, onesAndZeros) {
const wgpu::TextureComponentSwizzle previousWithOnesAndZeros{
.r = wgpu::ComponentSwizzle::Zero,
.g = wgpu::ComponentSwizzle::R,
.b = wgpu::ComponentSwizzle::One,
.a = wgpu::ComponentSwizzle::B,
};
const wgpu::TextureComponentSwizzle nextWithOnesAndZeros{
.r = wgpu::ComponentSwizzle::One,
.g = wgpu::ComponentSwizzle::Zero,
.b = wgpu::ComponentSwizzle::Undefined,
.a = wgpu::ComponentSwizzle::R,
};
const wgpu::TextureComponentSwizzle result{ filament::backend::composeSwizzle(
previousWithOnesAndZeros, nextWithOnesAndZeros) };
EXPECT_EQ(result.r, wgpu::ComponentSwizzle::One);
EXPECT_EQ(result.g, wgpu::ComponentSwizzle::Zero);
EXPECT_EQ(result.b, wgpu::ComponentSwizzle::One);
EXPECT_EQ(result.a, wgpu::ComponentSwizzle::Zero);
}
} // namespace test
@@ -124,13 +124,6 @@ public:
void setLocalTransforms(math::mat4f const* UTILS_NONNULL localTransforms,
size_t count, size_t offset = 0);
/**
* Returns the local transform for a given instance.
* @param index The index of the instance.
* @return The local transform of the instance.
*/
math::mat4f const& getLocalTransform(size_t index);
protected:
// prevent heap allocation
~InstanceBuffer() = default;
+53 -3
View File
@@ -87,6 +87,9 @@ public:
std::is_same_v<math::mat3f, T>
>;
template<typename T>
using is_supported_constant_parameter_t = std::enable_if_t<std::is_same_v<bool, T>>;
/**
* Creates a new MaterialInstance using another MaterialInstance as a template for initialization.
* The new MaterialInstance is an instance of the same Material of the template instance and
@@ -238,13 +241,13 @@ public:
/**
* Gets the value of a parameter by name.
*
*
* Note: Only supports non-texture parameters such as numeric and math types.
*
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*
*
* @see Material::hasParameter
*/
template<typename T>
@@ -262,6 +265,53 @@ public:
return getParameter<T>(name, strlen(name));
}
/**
* Set a mutable constant parameter by name.
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @param value Value of the parameter to set.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*/
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(const char* UTILS_NONNULL name, size_t nameLength, T const& value);
/** inline helper to provide the name as a null-terminated string literal */
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(StringLiteral const name, T const& value) {
setConstant<T>(name.data, name.size, value);
}
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(const char* UTILS_NONNULL name, T const& value) {
setConstant<T>(name, strlen(name), value);
}
/**
* Gets the value of a mutable constant parameter by name.
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*
* @see Material::hasConstant
*/
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(const char* UTILS_NONNULL name, size_t nameLength) const;
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(StringLiteral const name) const {
return getConstant<T>(name.data, name.size);
}
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(const char* UTILS_NONNULL name) const {
return getConstant<T>(name, strlen(name));
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
+1 -1
View File
@@ -81,7 +81,7 @@ public:
};
//! Use Builder to construct a RenderTarget object instance
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -783,13 +783,6 @@ public:
*/
size_t getPrimitiveCount(Instance instance) const noexcept;
/**
* Returns the number of instances for this renderable.
* @param instance Instance of the component obtained from getInstance().
* @return The number of instances.
*/
size_t getInstanceCount(Instance instance) const noexcept;
/**
* Changes the material instance binding for the given primitive.
*
+32 -43
View File
@@ -260,63 +260,52 @@ public:
* This flag also instructs the Metal backend to release the associated CAMetalDrawable on the
* completion handler thread.
*
* This flag has no effect if a custom CallbackHandler is passed or on backends other than Metal.
* This flag has no effect if a custom CallbackHandler is passed.
*
* @see setFrameScheduledCallback
*/
static constexpr uint64_t CALLBACK_DEFAULT_USE_METAL_COMPLETION_HANDLER = 1;
/**
* FrameScheduledCallback is a callback function that notifies an application about the status
* of a frame after Filament has finished its processing.
*
* The exact timing and semantics of this callback differ depending on the graphics backend in
* use.
*
* Metal Backend
* =============
*
* With the Metal backend, this callback signifies that Filament has completed all CPU-side
* processing for a frame and the frame is ready to be scheduled for presentation.
* FrameScheduledCallback is a callback function that notifies an application when Filament has
* completed processing a frame and that frame is ready to be scheduled for presentation.
*
* Typically, Filament is responsible for scheduling the frame's presentation to the SwapChain.
* If a SwapChain::FrameScheduledCallback is set, however, the application bears the
* responsibility of scheduling the frame for presentation by calling the
* backend::PresentCallable passed to the callback function. In this mode, Filament will *not*
* automatically schedule the frame for presentation.
*
* When using the Metal backend, if your application delays the call to the PresentCallable
* (e.g., by invoking it on a separate thread), you must ensure all PresentCallables have been
* called before shutting down the Filament Engine. You can guarantee this by calling
* Engine::flushAndWait() before Engine::shutdown(). This is necessary to ensure the Engine has
* a chance to clean up all memory related to frame presentation.
*
* Other Backends (OpenGL, Vulkan, WebGPU)
* =======================================
*
* On other backends, this callback serves as a notification that Filament has completed all
* CPU-side processing for a frame. Filament proceeds with its normal presentation logic
* automatically, and the PresentCallable passed to the callback is a no-op that can be safely
* ignored.
*
* General Behavior
* ================
* If a SwapChain::FrameScheduledCallback is set, however, the application bares the
* responsibility of scheduling a frame for presentation by calling the backend::PresentCallable
* passed to the callback function. Currently this functionality is only supported by the Metal
* backend.
*
* A FrameScheduledCallback can be set on an individual SwapChain through
* SwapChain::setFrameScheduledCallback. Each SwapChain can have only one callback set per
* frame. If setFrameScheduledCallback is called multiple times on the same SwapChain before
* Renderer::endFrame(), the most recent call effectively overwrites any previously set
* callback.
* SwapChain::setFrameScheduledCallback. If the callback is set for a given frame, then the
* SwapChain will *not* automatically schedule itself for presentation. Instead, the application
* must call the PresentCallable passed to the FrameScheduledCallback.
*
* The callback set by setFrameScheduledCallback is "latched" when Renderer::endFrame() is
* executed. At this point, the callback is fixed for the frame that was just encoded.
* Subsequent calls to setFrameScheduledCallback after endFrame() will apply to the next frame.
* Each SwapChain can have only one FrameScheduledCallback set per frame. If
* setFrameScheduledCallback is called multiple times on the same SwapChain before
* Renderer::endFrame(), the most recent call effectively overwrites any previously set
* callback. This allows the callback to be updated as needed before the frame has finished
* encoding.
*
* The "last" callback set by setFrameScheduledCallback gets "latched" when Renderer::endFrame()
* is executed. At this point, the state of the callback is fixed and is the one used for the
* frame that was just encoded. Subsequent changes to the callback using
* setFrameScheduledCallback after endFrame() apply to the next frame.
*
* Use \c setFrameScheduledCallback() (with default arguments) to unset the callback.
*
* @param handler Handler to dispatch the callback or nullptr for the default handler.
* @param callback Callback to be invoked when the frame processing is complete.
* @param flags See CALLBACK_DEFAULT_USE_METAL_COMPLETION_HANDLER
* If your application delays the call to the PresentCallable by, for example, calling it on a
* separate thread, you must ensure all PresentCallables have been called before shutting down
* the Filament Engine. You can do this by issuing an Engine::flushAndWait before calling
* Engine::shutdown. This is necessary to ensure the Filament Engine has had a chance to clean
* up all memory related to frame presentation.
*
* @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.
*
* @see CallbackHandler
* @see PresentCallable
+8 -14
View File
@@ -185,13 +185,12 @@ public:
* View.\n
* The View doesn't take ownership of the Camera pointer (which
* acts as a reference).
* If the camera isn't set, Renderer::render() will result in a no-op.
*
* @note
* There is no reference-counting.
* Make sure to dissociate a Camera from all Views before destroying it.
*/
void setCamera(Camera* UTILS_NULLABLE camera) noexcept;
void setCamera(Camera* UTILS_NONNULL camera) noexcept;
/**
* Returns whether a Camera is set.
@@ -202,17 +201,13 @@ public:
/**
* Returns the Camera currently associated with this View.
* Undefined behavior if hasCamera() is false.
* @return A reference to the Camera associated to this View if hasCamera() is true.
* @see hasCamera()
* @return A reference to the Camera associated to this View.
*/
Camera& getCamera() noexcept;
/**
* Returns the Camera currently associated with this View.
* Undefined behavior if hasCamera() is false.
* @return A reference to the Camera associated to this View.
* @see hasCamera()
*/
Camera const& getCamera() const noexcept {
return const_cast<View*>(this)->getCamera();
@@ -548,13 +543,12 @@ public:
* visible -- in this case, using a larger value can improve performance.
* e.g. when standing and looking straight, several meters of the ground
* isn't visible and if lights are expected to shine there, there is no
* point using a short zLightNear. This value is clamped between
* the camera near and far plane. (Default 5m).
* point using a short zLightNear. (Default 5m).
*
* @param zLightFar Distance from the camera after which lights are not expected to be visible.
* Similarly to zLightNear, setting this value properly can improve
* performance. This value is clamped between the camera near and far plane.
* (Default 100m).
* performance. (Default 100m).
*
*
* Together zLightNear and zLightFar must be chosen so that the visible influence of lights
* is spread between these two values.
@@ -769,9 +763,9 @@ public:
//! debugging: returns information about the froxel configuration
struct FroxelConfigurationInfo {
uint16_t width;
uint16_t height;
uint16_t depth;
uint8_t width;
uint8_t height;
uint8_t depth;
uint32_t viewportWidth;
uint32_t viewportHeight;
math::uint2 froxelDimension;
+2 -4
View File
@@ -18,10 +18,8 @@
#define TNT_FILAMENT_BUFFERPOOLALLOCATOR_H
#include <utils/Allocator.h>
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <memory>
#include <utility>
#include <stdint.h>
@@ -112,7 +110,7 @@ void* BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>:
if (UTILS_UNLIKELY(size > mSize)) {
clearInternal(); // free all buffers
// round to 4K allocations to help cutting down on calling malloc.
size_t const roundedSize = ((size + sizeof(Header)) + (ALLOCATION_ROUNDING - 1)) & ~(ALLOCATION_ROUNDING - 1);
size_t roundedSize = ((size + sizeof(Header)) + (ALLOCATION_ROUNDING - 1)) & ~(ALLOCATION_ROUNDING - 1);
mSize = roundedSize - sizeof(Header); // record the new buffer size
assert_invariant(mSize >= size);
}
@@ -121,7 +119,7 @@ void* BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>:
// larger than the requested size).
if (UTILS_UNLIKELY(mEntries.empty())) {
++mOutstandingBuffers;
Header* p = static_cast<Header*>(mAllocator.alloc(mSize + sizeof(Header), ALIGNMENT));
Header* p = (Header*)mAllocator.alloc(mSize + sizeof(Header), ALIGNMENT);
p->size = mSize;
return p + 1;
}
+91 -132
View File
@@ -19,29 +19,25 @@
#include "Allocators.h"
#include "Intersections.h"
#include "components/LightManager.h"
#include "details/Engine.h"
#include "details/Scene.h"
#include <private/filament/EngineEnums.h>
#include <private/utils/Tracing.h>
#include <private/backend/DriverApi.h>
#include <filament/Box.h>
#include <filament/View.h>
#include <filament/Viewport.h>
#include <backend/DriverEnums.h>
#include <utils/architecture.h>
#include <private/utils/Tracing.h>
#include <utils/BinaryTreeArray.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/JobSystem.h>
#include <utils/Logger.h>
#include <utils/ostream.h>
#include <utils/Slice.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <math/fast.h>
#include <math/mat3.h>
@@ -52,9 +48,9 @@
#include <math/vec4.h>
#include <algorithm>
#include <utils/architecture.h>
#include <array>
#include <cmath>
#include <functional>
#include <limits>
#include <type_traits>
#include <utility>
@@ -70,33 +66,24 @@ namespace filament {
using namespace backend;
// The number of froxel buffer entries is only limited by the maximum UBO size (see
// getFroxelBufferByteCount()), each entry consumes 4 bytes, so with a 16KB UBO, we get
// 4096 froxels.
// Increasing this value too much adds pressure on the record buffer, which is also limited
// to min(16K[ubo], 64K[uint16]) entries. In practice not all froxels are used.
constexpr size_t FROXEL_BUFFER_MAX_ENTRY_COUNT = 8192;
// Froxel buffer UBO is an array of uvec4. Make sure that the buffer is properly aligned.
static_assert(FROXEL_BUFFER_MAX_ENTRY_COUNT % 4 == 0u);
// TODO: these should come from a configuration object on View or Camera
static constexpr size_t FROXEL_SLICE_COUNT = 16;
static constexpr float FROXEL_FIRST_SLICE_DEPTH = 5;
static constexpr float FROXEL_LAST_SLICE_DISTANCE = 100;
// This is overridden by setOptions()
static constexpr float FROXEL_FIRST_SLICE_DEPTH_DEFAULT = 5; // 5m
static constexpr float FROXEL_LAST_SLICE_DISTANCE_DEFAULT = 100; // 100m
// The record buffer is limited by both the UBO size and our use of 16-bits indices.
constexpr size_t RECORD_BUFFER_ENTRY_COUNT = CONFIG_MINSPEC_UBO_SIZE; // 16 KiB UBO minspec
// Buffer needed for Froxelizer internal data structures (~256 KiB)
constexpr size_t PER_FROXELDATA_ARENA_SIZE = sizeof(float4) *
(FROXEL_BUFFER_MAX_ENTRY_COUNT +
FROXEL_BUFFER_MAX_ENTRY_COUNT + 3 +
FROXEL_SLICE_COUNT / 4 + 1);
(FROXEL_BUFFER_MAX_ENTRY_COUNT +
FROXEL_BUFFER_MAX_ENTRY_COUNT + 3 +
FROXEL_SLICE_COUNT / 4 + 1);
// Number of lights processed by one group (e.g. 32)
// number of lights processed by one group (e.g. 32)
static constexpr size_t LIGHT_PER_GROUP = sizeof(Froxelizer::LightGroupType) * 8;
// Number of groups (i.e. jobs) to use for froxelization (e.g. 8)
// number of groups (i.e. jobs) to use for froxelization (e.g. 8)
static constexpr size_t GROUP_COUNT =
(CONFIG_MAX_LIGHT_COUNT + LIGHT_PER_GROUP - 1) / LIGHT_PER_GROUP;
@@ -104,6 +91,14 @@ static constexpr size_t GROUP_COUNT =
static_assert(CONFIG_MAX_LIGHT_INDEX <= std::numeric_limits<Froxelizer::RecordBufferType>::max(),
"can't have more than 256 lights");
// Record buffer cannot be larger than 65K entries because froxels use uint16_t to store indices
// to it.
static_assert(RECORD_BUFFER_ENTRY_COUNT <= 65536,
"RecordBuffer cannot be larger than 65536 entries");
static_assert(RECORD_BUFFER_ENTRY_COUNT <= CONFIG_MINSPEC_UBO_SIZE,
"RecordBuffer cannot be larger than the UBO minspec (16KiB)");
struct Froxelizer::FroxelThreadData :
public std::array<LightGroupType, FROXEL_BUFFER_MAX_ENTRY_COUNT> {
};
@@ -129,25 +124,25 @@ size_t Froxelizer::getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexc
return std::min(FROXEL_BUFFER_MAX_ENTRY_COUNT * sizeof(FroxelEntry), targetSize);
}
size_t Froxelizer::getFroxelRecordBufferByteCount(FEngine::DriverApi& driverApi) noexcept {
// Make sure that targetSize is 16-byte aligned so that it'll fit properly into an array of
// uvec4. The maximum size is 64K entries, because we're using 16 bits indices.
size_t const targetSize = (driverApi.getMaxUniformBufferSize() / 16) * 16;
return std::min(size_t(std::numeric_limits<uint16_t>::max()), targetSize);
}
View::FroxelConfigurationInfo Froxelizer::getFroxelConfigurationInfo() const noexcept {
// this must return the configuration during the last update()
return mFroxelConfigurationInfo;
return { uint8_t(getFroxelCountX()),
uint8_t(getFroxelCountY()),
uint8_t(getFroxelCountZ()),
mViewport.width,
mViewport.height,
mFroxelDimension,
mZLightFar,
mLinearizer[0],
mProjection,
mClipTransform
};
}
Froxelizer::Froxelizer(FEngine& engine)
: mArena("froxel", PER_FROXELDATA_ARENA_SIZE),
mZLightNear(FROXEL_FIRST_SLICE_DEPTH_DEFAULT),
mZLightFar(FROXEL_LAST_SLICE_DISTANCE_DEFAULT),
mUserZLightNear(FROXEL_FIRST_SLICE_DEPTH_DEFAULT),
mUserZLightFar(FROXEL_LAST_SLICE_DISTANCE_DEFAULT) {
: mArena("froxel", PER_FROXELDATA_ARENA_SIZE),
mZLightNear(FROXEL_FIRST_SLICE_DEPTH),
mZLightFar(FROXEL_LAST_SLICE_DISTANCE)
{
static_assert(std::is_same_v<RecordBufferType, uint8_t>,
"Record Buffer must use bytes");
@@ -157,17 +152,10 @@ Froxelizer::Froxelizer(FEngine& engine)
return;
}
size_t const froxelBufferByteCount = getFroxelBufferByteCount(driverApi);
size_t const froxelBufferByteCount = getFroxelBufferByteCount(engine.getDriverApi());
mFroxelBufferEntryCount = froxelBufferByteCount / sizeof(FroxelEntry);
mFroxelBufferEntryCount &= ~0xF; // make sure it's a multiple of 16 (helps vectorizing)
assert_invariant(mFroxelBufferEntryCount >= 16); // that's also needed elsewhere
size_t const froxelRecordBufferByteCount = getFroxelRecordBufferByteCount(driverApi);
mFroxelRecordBufferEntryCount = froxelRecordBufferByteCount / sizeof(uint8_t);
assert_invariant(mFroxelRecordBufferEntryCount <= std::numeric_limits<uint16_t>::max());
mRecordsBuffer = driverApi.createBufferObject(
froxelRecordBufferByteCount,
mRecordsBuffer = driverApi.createBufferObject(RECORD_BUFFER_ENTRY_COUNT,
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
mFroxelsBuffer = driverApi.createBufferObject(
@@ -197,13 +185,14 @@ void Froxelizer::terminate(DriverApi& driverApi) noexcept {
}
void Froxelizer::setOptions(float const zLightNear, float const zLightFar) noexcept {
if (UTILS_UNLIKELY(mUserZLightNear != zLightNear || mUserZLightFar != zLightFar)) {
mUserZLightNear = zLightNear;
mUserZLightFar = zLightFar;
mDirtyFlags |= OPTIONS_CHANGED;
if (UTILS_UNLIKELY(mZLightNear != zLightNear || mZLightFar != zLightFar)) {
mZLightNear = zLightNear;
mZLightFar = zLightFar;
mDirtyFlags |= VIEWPORT_CHANGED;
}
}
void Froxelizer::setViewport(filament::Viewport const& viewport) noexcept {
if (UTILS_UNLIKELY(mViewport != viewport)) {
mViewport = viewport;
@@ -212,11 +201,10 @@ void Froxelizer::setViewport(filament::Viewport const& viewport) noexcept {
}
void Froxelizer::setProjection(const mat4f& projection,
float const near, UTILS_UNUSED float const far) noexcept {
if (UTILS_UNLIKELY(!fuzzyEqual(mProjection, projection) || mNear != near || mFar != far)) {
float const near, UTILS_UNUSED float far) noexcept {
if (UTILS_UNLIKELY(!fuzzyEqual(mProjection, projection))) {
mProjection = projection;
mNear = near;
mFar = far;
mDirtyFlags |= PROJECTION_CHANGED;
}
}
@@ -242,26 +230,26 @@ bool Froxelizer::prepare(
* the command stream.
*/
// froxel buffer (16 KiB with 4096 froxels)
// froxel buffer (~32 KiB)
mFroxelBufferUser = {
driverApi.allocatePod<FroxelEntry>(mFroxelBufferEntryCount),
mFroxelBufferEntryCount };
driverApi.allocatePod<FroxelEntry>(getFroxelBufferEntryCount()),
getFroxelBufferEntryCount() };
// record buffer (64 KiB max)
// record buffer (~16 KiB)
mRecordBufferUser = {
driverApi.allocatePod<RecordBufferType>(mFroxelRecordBufferEntryCount),
mFroxelRecordBufferEntryCount };
driverApi.allocatePod<RecordBufferType>(RECORD_BUFFER_ENTRY_COUNT),
RECORD_BUFFER_ENTRY_COUNT };
/*
* Temporary allocations for processing all froxel data
*/
// light records per froxel (~256 KiB with 4096 froxels)
// light records per froxel (~256 KiB)
mLightRecords = {
rootArenaScope.allocate<LightRecord>(getFroxelBufferEntryCount(), CACHELINE_SIZE),
getFroxelBufferEntryCount() };
// froxel thread data (~256KiB with 8192 max froxels and 256 lights)
// froxel thread data (~256 KiB)
mFroxelShardedData = {
rootArenaScope.allocate<FroxelThreadData>(GROUP_COUNT, CACHELINE_SIZE),
uint32_t(GROUP_COUNT)
@@ -289,7 +277,7 @@ void Froxelizer::computeFroxelLayout(
// calculate froxel dimension from FROXEL_BUFFER_ENTRY_COUNT_MAX and viewport
// - Start from the maximum number of froxels we can use in the x-y plane
constexpr size_t froxelSliceCount = FROXEL_SLICE_COUNT;
size_t const froxelSliceCount = FROXEL_SLICE_COUNT;
size_t const froxelPlaneCount = froxelBufferEntryCount / froxelSliceCount;
// - compute the number of square froxels we need in width and height, rounded down
// solving: | froxelCountX * froxelCountY == froxelPlaneCount
@@ -382,18 +370,6 @@ void Froxelizer::updateBoundingSpheres(
UTILS_NOINLINE
bool Froxelizer::update() noexcept {
bool uniformsNeedUpdating = false;
if (UTILS_UNLIKELY(mDirtyFlags & (OPTIONS_CHANGED|PROJECTION_CHANGED))) {
float const zLightFar = clamp(mUserZLightFar, mNear, mFar);
float zLightNear = clamp(mUserZLightNear, mNear, mFar);
zLightNear = std::min(zLightNear, zLightFar);
if (zLightFar != mZLightFar || zLightNear != mZLightNear) {
mDirtyFlags |= VIEWPORT_CHANGED;
mZLightNear = zLightNear;
mZLightFar = zLightFar;
}
}
if (UTILS_UNLIKELY(mDirtyFlags & VIEWPORT_CHANGED)) {
filament::Viewport const& viewport = mViewport;
@@ -524,19 +500,6 @@ bool Froxelizer::update() noexcept {
uniformsNeedUpdating = true;
}
assert_invariant(mZLightNear >= mNear);
if (UTILS_UNLIKELY(mDirtyFlags)) {
mFroxelConfigurationInfo = {
mFroxelCountX, mFroxelCountY, mFroxelCountZ,
mViewport.width, mViewport.height,
mFroxelDimension,
mZLightFar,
mLinearizer[0],
mProjection,
mClipTransform
};
}
mDirtyFlags = 0;
return uniformsNeedUpdating;
}
@@ -556,20 +519,20 @@ Froxel Froxelizer::getFroxelAt(size_t const x, size_t const y, size_t const z) c
}
UTILS_NOINLINE
size_t Froxelizer::findSliceZ(float const viewSpaceZ) const noexcept {
size_t Froxelizer::findSliceZ(float const z) const noexcept {
// The vastly common case is that z<0, so we always do the math for this case
// and we "undo" it below otherwise. This works because we're using fast::log2 which
// doesn't care if given a negative number (we'd have to use abs() otherwise).
// This whole function is now branch-less.
int s = int( fast::log2(-viewSpaceZ / mZLightFar) * mLinearizer[1] + float(mFroxelCountZ) );
int s = int( fast::log2(-z / mZLightFar) * mLinearizer[1] + float(mFroxelCountZ) );
// there are cases where z can be negative here, e.g.:
// - the light is visible, but its center is behind the camera
// - the camera's near is behind the camera (e.g. with shadowmap cameras)
// in that case just return the first slice
s = viewSpaceZ < 0 ? s : 0;
s = z < 0 ? s : 0;
// clamp between [0, mFroxelCountZ)
return size_t(clamp(s, 0, mFroxelCountZ - 1));
@@ -588,10 +551,10 @@ std::pair<size_t, size_t> Froxelizer::clipToIndices(float2 const& clip) const no
void Froxelizer::commit(DriverApi& driverApi) {
// send data to GPU
driverApi.updateBufferObject(mFroxelsBuffer,
{ mFroxelBufferUser.data(), mFroxelBufferEntryCount * sizeof(FroxelEntry) }, 0);
{ mFroxelBufferUser.data(), getFroxelBufferEntryCount() * sizeof(FroxelEntry) }, 0);
driverApi.updateBufferObject(mRecordsBuffer,
{ mRecordBufferUser.data(), mFroxelRecordBufferEntryCount }, 0);
{ mRecordBufferUser.data(), RECORD_BUFFER_ENTRY_COUNT }, 0);
#ifndef NDEBUG
mFroxelBufferUser.clear();
@@ -618,7 +581,7 @@ void Froxelizer::froxelizeLights(FEngine& engine,
// go through every light for that froxel
for (size_t i = 0; i < entry.count(); i++) {
// get the light index
assert_invariant(entry.offset() + i < mFroxelRecordBufferEntryCount);
assert_invariant(entry.offset() + i < RECORD_BUFFER_ENTRY_COUNT);
size_t const lightIndex = recordBufferUser[entry.offset() + i];
assert_invariant(lightIndex <= CONFIG_MAX_LIGHT_INDEX);
@@ -633,7 +596,7 @@ void Froxelizer::froxelizeLights(FEngine& engine,
void Froxelizer::froxelizeLoop(FEngine& engine,
const mat4f& UTILS_RESTRICT viewMatrix,
const FScene::LightSoa& UTILS_RESTRICT lightData) const noexcept {
const FScene::LightSoa& UTILS_RESTRICT lightData) noexcept {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
Slice<FroxelThreadData> froxelThreadData = mFroxelShardedData;
@@ -705,20 +668,18 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
Slice<FroxelThreadData> const froxelThreadData = mFroxelShardedData;
// Convert froxel data from N groups of M bits to LightRecord::bitset, so we can
// convert froxel data from N groups of M bits to LightRecord::bitset, so we can
// easily compare adjacent froxels, for compaction. The conversion loops below get
// inlined and vectorized in release builds.
// this gets very well vectorized...
Slice records(mLightRecords);
for (size_t j = 0, jc = getFroxelBufferEntryCount() ; j < jc; j++) {
using container_type = LightRecord::bitset::container_type;
constexpr size_t r = sizeof(container_type) / sizeof(LightGroupType);
UTILS_UNROLL
Slice<LightRecord> records(mLightRecords);
for (size_t j = 0, jc = getFroxelBufferEntryCount(); j < jc; j++) {
for (size_t i = 0; i < LightRecord::bitset::WORLD_COUNT; i++) {
using container_type = LightRecord::bitset::container_type;
constexpr size_t r = sizeof(container_type) / sizeof(LightGroupType);
container_type b = froxelThreadData[i * r][j];
UTILS_UNROLL
for (size_t k = 0; k < r; k++) {
b |= (container_type(froxelThreadData[i * r + k][j]) << (LIGHT_PER_GROUP * k));
}
@@ -737,21 +698,19 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
const size_t froxelCountX = mFroxelCountX;
RecordBufferType* const UTILS_RESTRICT froxelRecords = mRecordBufferUser.data();
// Initialize the first record with all lights in the scene -- this will be used only if
// initialize the first record with all lights in the scene -- this will be used only if
// we run out of record space.
// Our light count cannot be larger than 255 because it's stored in a uint8_t. This should
// be guaranteed by CONFIG_MAX_LIGHT_COUNT
assert_invariant(allLights.count() <= std::numeric_limits<uint8_t>::max());
const uint8_t allLightsCount = allLights.count();
const uint8_t allLightsCount = (uint8_t)std::min(size_t(255), allLights.count());
offset += allLightsCount;
allLights.forEachSetBit([p = froxelRecords](size_t l) mutable {
allLights.forEachSetBit([point = froxelRecords, froxelRecords](size_t l) mutable {
// make sure to keep this code branch-less
const size_t word = l / LIGHT_PER_GROUP;
const size_t bit = l % LIGHT_PER_GROUP;
l = (bit * GROUP_COUNT) | (word % GROUP_COUNT);
*p++ = RecordBufferType(l);
*point = (RecordBufferType)l;
// we need to "cancel" the write operation if we have more than 255 spot or point lights
// (this is a limitation of the data type used to store the light counts per froxel)
point += (point - froxelRecords < 255) ? 1 : 0;
});
// how many froxel record entries were reused (for debugging)
@@ -765,13 +724,11 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
}
// We have a limitation of 255 spot + 255 point lights per froxel.
assert_invariant(b.lights.count() <= std::numeric_limits<uint8_t>::max());
// note: initializer list for union cannot have more than one element
FroxelEntry entry{ offset, uint8_t(b.lights.count()) };
FroxelEntry entry{ offset, uint8_t(std::min(size_t(255), b.lights.count())) };
const size_t lightCount = entry.count();
if (UTILS_UNLIKELY(offset + lightCount >= mFroxelRecordBufferEntryCount)) {
if (UTILS_UNLIKELY(offset + lightCount >= RECORD_BUFFER_ENTRY_COUNT)) {
// DLOG(INFO) << "out of space: " << i << ", at " << offset;
// note: instead of dropping froxels we could look for similar records we've already
// filed up.
@@ -786,12 +743,15 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
// iterate the bitfield
auto * const beginPoint = froxelRecords + offset;
b.lights.forEachSetBit([p = beginPoint](size_t l) mutable {
b.lights.forEachSetBit([point = beginPoint, beginPoint](size_t l) mutable {
// make sure to keep this code branch-less
const size_t word = l / LIGHT_PER_GROUP;
const size_t bit = l % LIGHT_PER_GROUP;
l = (bit * GROUP_COUNT) | (word % GROUP_COUNT);
*p++ = RecordBufferType(l);
*point = RecordBufferType(l);
// we need to "cancel" the write operation if we have more than 255 spot or point lights
// (this is a limitation of the data type used to store the light counts per froxel)
point += (point - beginPoint < 255) ? 1 : 0;
});
offset += lightCount;
@@ -832,7 +792,7 @@ static float2 project(mat4f const& p, float3 const& v) noexcept {
void Froxelizer::froxelizePointAndSpotLight(
FroxelThreadData& froxelThread, size_t bit,
mat4f const& UTILS_RESTRICT projection,
mat4f const& UTILS_RESTRICT p,
const LightParams& UTILS_RESTRICT light) const noexcept {
if (UTILS_UNLIKELY(light.position.z + light.radius < -mZLightFar)) { // z values are negative
@@ -863,14 +823,14 @@ void Froxelizer::froxelizePointAndSpotLight(
// e.g.: we could only do the z-min/max which is much easier to compute.
const float2 pts[8] = {
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1, 1 }, znear }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1,-1 }, znear }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{-1, 1 }, znear }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{-1,-1 }, znear }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1, 1 }, zfar }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1,-1 }, zfar }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{-1, 1 }, zfar }),
project(projection, { aabb.center.xy + aabb.halfExtent.xy * float2{-1,-1 }, zfar }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1, 1 }, znear }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1,-1 }, znear }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{-1, 1 }, znear }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{-1,-1 }, znear }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1, 1 }, zfar }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{ 1,-1 }, zfar }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{-1, 1 }, zfar }),
project(p, { aabb.center.xy + aabb.halfExtent.xy * float2{-1,-1 }, zfar }),
};
float2 pmin = std::numeric_limits<float>::max();
@@ -889,7 +849,6 @@ void Froxelizer::froxelizePointAndSpotLight(
assert_invariant(x0 <= x1);
assert_invariant(y0 <= y1);
assert_invariant(z0 <= z1);
#endif
const size_t zcenter = findSliceZ(s.z);
@@ -909,7 +868,7 @@ void Froxelizer::froxelizePointAndSpotLight(
// the sphere (light) intersects this slice's plane, and we now have a new smaller
// sphere centered there. Now, find x & y slices that contain the sphere's center
// (note: this changes with the Z slices)
const float2 clip = project(projection, cz.xyz);
const float2 clip = project(p, cz.xyz);
auto const [xcenter, ycenter] = clipToIndices(clip);
for (size_t iy = y0; iy <= y1; ++iy) {
+33 -57
View File
@@ -22,31 +22,31 @@
#include "details/Scene.h"
#include "details/Engine.h"
#include "private/filament/EngineEnums.h"
#include "private/filament/UibStructs.h"
#include <filament/View.h>
#include <filament/Viewport.h>
#include <backend/Handle.h>
#include <math/mat4.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/bitset.h>
#include <utils/Slice.h>
#include <cstdint>
#include <cstddef>
#include <limits>
#include <utility>
#include <math/mat4.h>
#include <math/vec2.h>
#include <math/vec4.h>
namespace filament {
// The number of froxel buffer entries is determined by max UBO size (see
// getFroxelBufferByteCount()). We also introduce the limit below because increasing the number of
// froxels adds more pressure on the "record buffer" which stores the light indices per froxel. The
// record buffer is limited to min(16K[ubo], 64K[uint16]) entries. In practice some froxels are not
// used, so we can store more.
constexpr size_t FROXEL_BUFFER_MAX_ENTRY_COUNT = 8192;
// Froxel buffer UBO is an array of uvec4. Make sure that the buffer is properly aligned.
static_assert(FROXEL_BUFFER_MAX_ENTRY_COUNT % 4 == 0u);
class FEngine;
class FCamera;
class FTexture;
@@ -89,12 +89,12 @@ public:
void terminate(backend::DriverApi& driverApi) noexcept;
// GPU buffer containing records. Valid after construction.
// gpu buffer containing records. valid after construction.
backend::Handle<backend::HwBufferObject> getRecordBuffer() const noexcept {
return mRecordsBuffer;
}
// GPU buffer containing froxels. Valid after construction.
// gpu buffer containing froxels. valid after construction.
backend::Handle<backend::HwBufferObject> getFroxelBuffer() const noexcept {
return mFroxelsBuffer;
}
@@ -110,12 +110,10 @@ public:
* projection camera projection matrix
* projectionNear near plane
* projectionFar far plane
* clipTransform [debugging] the clipTransform that's already included in the projection
*
* return true if updateUniforms() needs to be called
*/
bool prepare(backend::DriverApi& driverApi, RootArenaScope& rootArenaScope,
Viewport const& viewport,
bool prepare(backend::DriverApi& driverApi, RootArenaScope& rootArenaScope, Viewport const& viewport,
const math::mat4f& projection, float projectionNear, float projectionFar,
math::float4 const& clipTransform) noexcept;
@@ -127,20 +125,16 @@ public:
float getLightFar() const noexcept { return mZLightFar; }
// Update Records and Froxels texture with lights data. This is thread-safe.
// update Records and Froxels texture with lights data. this is thread-safe.
void froxelizeLights(FEngine& engine, math::mat4f const& viewMatrix,
const FScene::LightSoa& lightData) noexcept;
void updateUniforms(PerViewUib& s) const {
void updateUniforms(PerViewUib& s) {
s.zParams = mParamsZ;
s.fParams = mParamsF;
s.froxelCountXY = math::float2{ mViewport.width, mViewport.height } / mFroxelDimension;
}
static size_t getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexcept;
static size_t getFroxelRecordBufferByteCount(FEngine::DriverApi& driverApi) noexcept;
// send froxel data to GPU
void commit(backend::DriverApi& driverApi);
@@ -150,35 +144,30 @@ public:
*/
struct FroxelEntry {
FroxelEntry(uint16_t const offset, uint8_t const count) noexcept
inline FroxelEntry(uint16_t const offset, uint8_t const count) noexcept
: u32((offset << 16) | count) { }
uint8_t count() const noexcept { return u32 & 0xFFu; }
uint16_t offset() const noexcept { return u32 >> 16u; }
inline uint8_t count() const noexcept { return u32 & 0xFFu; }
inline uint16_t offset() const noexcept { return u32 >> 16u; }
uint32_t u32 = 0;
};
static_assert(sizeof(FroxelEntry) == 4u);
// We can't change this easily because the shader expects 16 indices per uint4
// we can't change this easily because the shader expects 16 indices per uint4
using RecordBufferType = uint8_t;
const utils::Slice<FroxelEntry>& getFroxelBufferUser() const { return mFroxelBufferUser; }
const utils::Slice<RecordBufferType>& getRecordBufferUser() const { return mRecordBufferUser; }
// This is chosen so froxelizePointAndSpotLight() vectorizes 4 froxel tests / spotlight
// this is chosen so froxelizePointAndSpotLight() vectorizes 4 froxel tests / spotlight
// with 256 lights this implies 8 jobs (256 / 32) for froxelization.
using LightGroupType = uint32_t;
static size_t getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexcept;
View::FroxelConfigurationInfo getFroxelConfigurationInfo() const noexcept;
private:
size_t getFroxelBufferEntryCount() const noexcept {
// We guarantee that mFroxelBufferEntryCount is a multiple of 16. With this knowledge
// the compiler can do a much better job at vectorizing. For similar reasons, it's
// important to keep mFroxelBufferEntryCount an uint32_t (as opposed to a size_t).
assert_invariant((mFroxelBufferEntryCount & 0xF) == 0);
UTILS_ASSUME((mFroxelBufferEntryCount & 0xF) == 0);
UTILS_ASSUME(mFroxelBufferEntryCount >= 16);
return mFroxelBufferEntryCount;
}
@@ -216,7 +205,7 @@ private:
bool update() noexcept;
void froxelizeLoop(FEngine& engine,
math::mat4f const& viewMatrix, const FScene::LightSoa& lightData) const noexcept;
math::mat4f const& viewMatrix, const FScene::LightSoa& lightData) noexcept;
void froxelizeAssignRecordsCompress() noexcept;
@@ -255,28 +244,21 @@ private:
LinearAllocatorArena mArena; // ~256 KiB
// 4096 froxels fits in a 16KiB buffer, the minimum guaranteed in GLES 3.x and Vulkan 1.1
uint32_t mFroxelBufferEntryCount = 4096;
// 16384 entries is our minimum with a 16KiB buffer
uint32_t mFroxelRecordBufferEntryCount = 16384;
size_t mFroxelBufferEntryCount = 4096;
// allocations in the private froxel arena
float* mDistancesZ = nullptr;
math::float4* mPlanesX = nullptr;
math::float4* mPlanesY = nullptr;
math::float4* mBoundingSpheres = nullptr; // 64 KiB w/ 4096 froxels
math::float4* mBoundingSpheres = nullptr; // 128 KiB w/ 8192 froxels
// allocations in the per frame arena
// max | real | size
// 8192 | 4096 | 512 KiB
// 8192 | 8192 | 768 KiB
// 65536 | 65536 | 6.0 MiB
utils::Slice<LightRecord> mLightRecords; // 256 KiB w/ 256 lights and 4096 froxels
utils::Slice<FroxelThreadData> mFroxelShardedData; // 256 KiB w/ 256 lights and 8192 max froxels
utils::Slice<FroxelThreadData> mFroxelShardedData; // 256 KiB w/ 256 lights and 8192 froxels
utils::Slice<FroxelEntry> mFroxelBufferUser; // 32 KiB w/ 8192 froxels
utils::Slice<LightRecord> mLightRecords; // 256 KiB w/ 256 lights
// allocations in the command stream
utils::Slice<FroxelEntry> mFroxelBufferUser; // 16 KiB w/ 4096 froxels
utils::Slice<RecordBufferType> mRecordBufferUser; // 16 KiB to 64 KiB
utils::Slice<RecordBufferType> mRecordBufferUser; // 16 KiB
uint16_t mFroxelCountX = 0;
uint16_t mFroxelCountY = 0;
@@ -297,21 +279,15 @@ private:
math::float4 mParamsZ = {};
math::uint3 mParamsF = {};
float mNear = 0.0f; // camera near
float mFar = 0.0f; // culling camera far
float mZLightNear;
float mZLightFar;
float mUserZLightNear;
float mUserZLightFar;
// track if we need to update our internal state before froxelizing
uint8_t mDirtyFlags = 0;
enum {
VIEWPORT_CHANGED = 0x01,
PROJECTION_CHANGED = 0x02,
OPTIONS_CHANGED = 0x04
PROJECTION_CHANGED = 0x02
};
View::FroxelConfigurationInfo mFroxelConfigurationInfo{};
};
} // namespace filament
-10
View File
@@ -16,12 +16,6 @@
#include "details/InstanceBuffer.h"
#include <filament/InstanceBuffer.h>
#include <math/mat4.h>
#include <cstddef>
namespace filament {
size_t InstanceBuffer::getInstanceCount() const noexcept {
@@ -33,8 +27,4 @@ void InstanceBuffer::setLocalTransforms(
downcast(this)->setLocalTransforms(localTransforms, count, offset);
}
math::mat4f const& InstanceBuffer::getLocalTransform(size_t index) {
return downcast(this)->getLocalTransform(index);
}
} // namespace filament
+40
View File
@@ -233,6 +233,46 @@ template UTILS_PUBLIC mat3f MaterialInstance::getParameter<mat3f> (const ch
// ------------------------------------------------------------------------------------------------
template<>
inline void FMaterialInstance::setConstantImpl<bool>(std::string_view const name, bool const& value) {
std::optional<uint32_t> id = mMaterial->getMutableConstantId(name);
FILAMENT_CHECK_PRECONDITION(id.has_value()) << "No mutable constant with name " << name;
mConstants.set(*id, value);
}
template<typename T, typename>
void MaterialInstance::setConstant(const char* name, size_t nameLength, T const& value) {
downcast(this)->setConstantImpl({ name, nameLength }, value);
}
// Explicit template instantiation of our supported types.
//
// Mutable spec constants will probably only ever allow bools, but it's nice to keep the API
// forwards-compatible.
template UTILS_PUBLIC void MaterialInstance::setConstant<bool>(const char* name, size_t nameLength, bool const& v);
// ------------------------------------------------------------------------------------------------
template<>
inline bool FMaterialInstance::getConstantImpl<bool>(std::string_view const name) const {
std::optional<uint32_t> id = mMaterial->getMutableConstantId(name);
FILAMENT_CHECK_PRECONDITION(id.has_value()) << "No mutable constant with name " << name;
return mConstants[*id];
}
template<typename T, typename>
T MaterialInstance::getConstant(const char* name, size_t nameLength) const {
return downcast(this)->getConstantImpl<T>({ name, nameLength });
}
// Explicit template instantiation of our supported types.
//
// Mutable spec constants will probably only ever allow bools, but it's nice to keep the API
// forwards-compatible.
template UTILS_PUBLIC bool MaterialInstance::getConstant<bool>(const char* name, size_t nameLength) const;
// ------------------------------------------------------------------------------------------------
Material const* MaterialInstance::getMaterial() const noexcept {
return downcast(this)->getMaterial();
}
+37
View File
@@ -229,6 +229,11 @@ bool MaterialParser::getConstants(FixedCapacityVector<MaterialConstant>* contain
return get<ChunkMaterialConstants>(container);
}
bool MaterialParser::getMutableConstants(
FixedCapacityVector<MaterialMutableConstant>* container) const noexcept {
return get<ChunkMaterialMutableConstants>(container);
}
bool MaterialParser::getPushConstants(CString* structVarName,
FixedCapacityVector<MaterialPushConstant>* value) const noexcept {
auto [start, end] = mImpl.mChunkContainer.getChunkRange(MaterialPushConstants);
@@ -761,6 +766,38 @@ bool ChunkMaterialConstants::unflatten(Unflattener& unflattener,
return true;
}
bool ChunkMaterialMutableConstants::unflatten(Unflattener& unflattener,
FixedCapacityVector<MaterialMutableConstant>* materialConstants) {
assert_invariant(materialConstants);
// Read number of constants.
uint64_t numConstants = 0;
if (!unflattener.read(&numConstants)) {
return false;
}
materialConstants->reserve(numConstants);
materialConstants->resize(numConstants);
for (uint64_t i = 0; i < numConstants; i++) {
CString constantName;
bool defaultValue;
if (!unflattener.read(&constantName)) {
return false;
}
if (!unflattener.read(&defaultValue)) {
return false;
}
(*materialConstants)[i].name = std::move(constantName);
(*materialConstants)[i].defaultValue = defaultValue;
}
return true;
}
bool ChunkMaterialPushConstants::unflatten(Unflattener& unflattener,
CString* structVarName,
FixedCapacityVector<MaterialPushConstant>* materialPushConstants) {
+10
View File
@@ -49,6 +49,7 @@ class BufferInterfaceBlock;
class SamplerInterfaceBlock;
struct SubpassInfo;
struct MaterialConstant;
struct MaterialMutableConstant;
struct MaterialPushConstant;
class MaterialParser {
@@ -79,6 +80,8 @@ public:
bool getShaderModels(uint32_t* value) const noexcept;
bool getMaterialProperties(uint64_t* value) const noexcept;
bool getConstants(utils::FixedCapacityVector<MaterialConstant>* value) const noexcept;
bool getMutableConstants(utils::FixedCapacityVector<MaterialMutableConstant>* value)
const noexcept;
bool getPushConstants(utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* value) const noexcept;
@@ -238,6 +241,13 @@ struct ChunkMaterialConstants {
static filamat::ChunkType const tag = filamat::MaterialConstants;
};
struct ChunkMaterialMutableConstants {
static bool unflatten(filaflat::Unflattener& unflattener,
utils::FixedCapacityVector<MaterialMutableConstant>* materialConstants);
using Container = utils::FixedCapacityVector<MaterialMutableConstant>;
static filamat::ChunkType const tag = filamat::MaterialMutableConstants;
};
struct ChunkMaterialPushConstants {
static bool unflatten(filaflat::Unflattener& unflattener, utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* materialPushConstants);
+7 -2
View File
@@ -199,6 +199,8 @@ FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
loadMaterial(engine);
}
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) },
// TODO(exv): allow post process materials to use mutable spec constants?
Program::MutableSpecConstantsInfo(0),
CompilerPriorityQueue::CRITICAL);
return mMaterial;
}
@@ -344,7 +346,7 @@ void PostProcessManager::init() noexcept {
engine.getDummyMorphTargetBuffer()->getTangentsHandle(), {});
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, engine.getZeroTexture(),
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, engine.getZeroTextureArray(),
{});
mSsrPassDescriptorSet.init(engine);
@@ -465,7 +467,10 @@ UTILS_NOINLINE
PipelineState PostProcessManager::getPipelineState(
FMaterial const* const ma, PostProcessVariant variant) const noexcept {
return {
.program = ma->getProgram(Variant{ Variant::type_t(variant) }),
.program = ma->getProgram(Variant{ Variant::type_t(variant) },
// TODO(exv): allow post process materials to use mutable spec constants?
Program::MutableSpecConstantsInfo(0)
),
.vertexBufferInfo = mFullScreenQuadVbih,
.pipelineLayout = {
.setLayout = {
+5 -2
View File
@@ -243,7 +243,9 @@ void RenderPass::appendCommands(FEngine const& engine,
for (Command const* first = curr, *last = curr + commandCount ; first != last ; ++first) {
if (UTILS_LIKELY((first->key & CUSTOM_MASK) == uint64_t(CustomCommand::PASS))) {
auto ma = first->info.mi->getMaterial();
ma->prepareProgram(first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
ma->prepareProgram(first->info.materialVariant,
first->info.mi->getMutableSpecConstants(),
CompilerPriorityQueue::CRITICAL);
}
}
}
@@ -1096,7 +1098,8 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
}
assert_invariant(ma);
pipeline.program = ma->getProgram(info.materialVariant);
pipeline.program = ma->getProgram(info.materialVariant,
info.mi->getMutableSpecConstants());
if (UTILS_UNLIKELY(memcmp(&pipeline, &currentPipeline, sizeof(PipelineState)) != 0)) {
currentPipeline = pipeline;
-4
View File
@@ -108,10 +108,6 @@ size_t RenderableManager::getPrimitiveCount(Instance const instance) const noexc
return downcast(this)->getPrimitiveCount(instance, 0);
}
size_t RenderableManager::getInstanceCount(Instance instance) const noexcept {
return downcast(this)->getInstanceCount(instance);
}
void RenderableManager::setMaterialInstanceAt(Instance const instance,
size_t const primitiveIndex, MaterialInstance const* materialInstance) {
downcast(this)->setMaterialInstanceAt(instance, 0, primitiveIndex, downcast(materialInstance));
+7 -5
View File
@@ -148,7 +148,8 @@ RenderTargetHandle ResourceAllocator::createRenderTarget(const char* name,
uint8_t const samples, uint8_t const layerCount, MRT const color, TargetBufferInfo const depth,
TargetBufferInfo const stencil) noexcept {
auto handle = mBackend.createRenderTarget(targetBufferFlags,
width, height, samples ? samples : 1u, layerCount, color, depth, stencil, CString(name));
width, height, samples ? samples : 1u, layerCount, color, depth, stencil);
mBackend.setDebugTag(handle.getId(), CString{ name });
return handle;
}
@@ -183,25 +184,26 @@ TextureHandle ResourceAllocator::createTexture(const char* name,
} else {
// we don't, allocate a new texture and populate the in-use list
handle = mBackend.createTexture(
target, levels, format, samples, width, height, depth, usage, CString(name));
target, levels, format, samples, width, height, depth, usage);
if (swizzle != defaultSwizzle) {
TextureHandle swizzledHandle = mBackend.createTextureViewSwizzle(
handle, swizzle[0], swizzle[1], swizzle[2], swizzle[3], CString(name));
handle, swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
mBackend.destroyTexture(handle);
handle = swizzledHandle;
}
}
} else {
handle = mBackend.createTexture(
target, levels, format, samples, width, height, depth, usage, CString(name));
target, levels, format, samples, width, height, depth, usage);
if (swizzle != defaultSwizzle) {
TextureHandle swizzledHandle = mBackend.createTextureViewSwizzle(
handle, swizzle[0], swizzle[1], swizzle[2], swizzle[3], CString(name));
handle, swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
mBackend.destroyTexture(handle);
handle = swizzledHandle;
}
}
mDisposer->checkout(handle, key);
mBackend.setDebugTag(handle.getId(), CString{ name });
return handle;
}
+1 -13
View File
@@ -27,19 +27,7 @@ bool ZstdHelper::isCompressed(const void* src, size_t src_size) noexcept {
if (src_size < 4) {
return false;
}
// `src` may not be aligned to 4 bytes, which is violating the alignment requirement of
// `UndefinedBehaviorSanitizer: misaligned-pointer-use`. So reconstruct the 32-bit integer from
// bytes in little-endian order as the expected byte sequence is 28 B5 2F FD and
// ZSTD_MAGICNUMBER refers to 0xFD2FB528. This should work correctly on both little-endian and
// big-endian systems.
const auto* p = static_cast<const uint8_t*>(src);
const uint32_t magic =
(uint32_t)p[0] |
(uint32_t)(p[1] << 8) |
(uint32_t)(p[2] << 16) |
(uint32_t)(p[3] << 24);
const uint32_t magic = *static_cast<const uint32_t*>(src);
return magic == ZSTD_MAGICNUMBER;
}
+12 -21
View File
@@ -434,18 +434,6 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi
mBoneIndicesAndWeightsCount = pairsCount; // only part of mBoneIndicesAndWeights is used for real data
}
RenderableManager::Builder& RenderableManager::Builder::instances(size_t const instanceCount) noexcept {
mImpl->mInstanceCount = clamp((unsigned int)instanceCount, 1u, 32767u);
return *this;
}
RenderableManager::Builder& RenderableManager::Builder::instances(
size_t const instanceCount, InstanceBuffer* instanceBuffer) noexcept {
mImpl->mInstanceCount = clamp(instanceCount, (size_t)1, CONFIG_MAX_INSTANCES);
mImpl->mInstanceBuffer = downcast(instanceBuffer);
return *this;
}
RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity const entity) {
bool isEmpty = true;
@@ -531,6 +519,18 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng
return Success;
}
RenderableManager::Builder& RenderableManager::Builder::instances(size_t const instanceCount) noexcept {
mImpl->mInstanceCount = clamp((unsigned int)instanceCount, 1u, 32767u);
return *this;
}
RenderableManager::Builder& RenderableManager::Builder::instances(
size_t const instanceCount, InstanceBuffer* instanceBuffer) noexcept {
mImpl->mInstanceCount = clamp(instanceCount, (size_t)1, CONFIG_MAX_INSTANCES);
mImpl->mInstanceBuffer = downcast(instanceBuffer);
return *this;
}
// ------------------------------------------------------------------------------------------------
FRenderableManager::FRenderableManager(FEngine& engine) noexcept : mEngine(engine) {
@@ -1006,13 +1006,4 @@ size_t FRenderableManager::getPrimitiveCount(Instance const instance, uint8_t co
return getRenderPrimitives(instance, level).size();
}
size_t FRenderableManager::getInstanceCount(Instance const instance) const noexcept {
if (instance) {
InstancesInfo const& info = mManager[instance].instances;
return info.count;
}
return 0;
}
} // namespace filament
@@ -199,7 +199,6 @@ public:
size_t getLevelCount(Instance) const noexcept { return 1u; }
size_t getPrimitiveCount(Instance instance, uint8_t level) const noexcept;
size_t getInstanceCount(Instance instance) const noexcept;
void setMaterialInstanceAt(Instance instance, uint8_t level,
size_t primitiveIndex, FMaterialInstance const* materialInstance);
void clearMaterialInstanceAt(Instance instance, uint8_t level, size_t primitiveIndex);
+4 -1
View File
@@ -76,7 +76,10 @@ FBufferObject::FBufferObject(FEngine& engine, const Builder& builder)
: mByteCount(builder->mByteCount), mBindingType(builder->mBindingType) {
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createBufferObject(builder->mByteCount, builder->mBindingType,
backend::BufferUsage::STATIC, builder.getName());
backend::BufferUsage::STATIC);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
void FBufferObject::terminate(FEngine& engine) {
+4
View File
@@ -733,6 +733,7 @@ public:
CORRECTNESS_ASSERTION_DEFAULT;
bool assert_material_instance_texture_descriptor_set_compatible =
CORRECTNESS_ASSERTION_DEFAULT;
bool assert_texture_format_mipmappable = CORRECTNESS_ASSERTION_DEFAULT;
bool assert_texture_can_generate_mipmap = CORRECTNESS_ASSERTION_DEFAULT;
} debug;
} engine;
@@ -796,6 +797,9 @@ public:
{ "engine.debug.assert_material_instance_texture_descriptor_set_compatible",
"Assert that the textures in a material instance are compatible with descriptor set.",
&features.engine.debug.assert_material_instance_texture_descriptor_set_compatible, false },
{ "engine.debug.assert_texture_format_mipmappable",
"Assert if a texture (with levels > 1) that the format is mipmappable.",
&features.engine.debug.assert_texture_format_mipmappable, false },
{ "engine.debug.assert_texture_can_generate_mipmap",
"Assert if a texture has the correct usage set for generating mipmaps.",
&features.engine.debug.assert_texture_can_generate_mipmap, false },
+4 -2
View File
@@ -83,8 +83,10 @@ FIndexBuffer::FIndexBuffer(FEngine& engine, const Builder& builder)
mHandle = driver.createIndexBuffer(
backend::ElementType(builder->mIndexType),
uint32_t(builder->mIndexCount),
backend::BufferUsage::STATIC,
std::move(name));
backend::BufferUsage::STATIC);
if (!name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
void FIndexBuffer::terminate(FEngine& engine) {
+33 -26
View File
@@ -29,8 +29,6 @@
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Panic.h>
#include <utils/StaticString.h>
@@ -89,7 +87,7 @@ InstanceBuffer* InstanceBuffer::Builder::build(Engine& engine) const {
// ------------------------------------------------------------------------------------------------
FInstanceBuffer::FInstanceBuffer(FEngine&, const Builder& builder)
FInstanceBuffer::FInstanceBuffer(FEngine& engine, const Builder& builder)
: mName(builder.getName()) {
mInstanceCount = builder->mInstanceCount;
@@ -100,11 +98,22 @@ FInstanceBuffer::FInstanceBuffer(FEngine&, const Builder& builder)
memcpy(mLocalTransforms.data(), builder->mLocalTransforms,
sizeof(math::mat4f) * mInstanceCount);
}
// Allocate our instance buffer. We always allocate a size to match
// PerRenderableUib, regardless of the number of instances. This is because the buffer
// will get bound to the PER_RENDERABLE UBO, and we can't bind a buffer smaller than the
// full size of the UBO.
DriverApi& driver = engine.getDriverApi();
mHandle = driver.createBufferObject(sizeof(PerRenderableUib),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
if (auto name = mName; !name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
void FInstanceBuffer::terminate(FEngine&) {
mHandle.clear();
mOffset = 0;
void FInstanceBuffer::terminate(FEngine& engine) {
DriverApi& driver = engine.getDriverApi();
driver.destroyBufferObject(std::move(mHandle));
}
FInstanceBuffer::~FInstanceBuffer() noexcept = default;
@@ -118,30 +127,28 @@ void FInstanceBuffer::setLocalTransforms(
memcpy(mLocalTransforms.data() + offset, localTransforms, sizeof(math::mat4f) * count);
}
math::mat4f const& FInstanceBuffer::getLocalTransform(size_t index) const noexcept {
FILAMENT_CHECK_PRECONDITION(index < mInstanceCount)
<< "getLocalTransform overflow: 'index (" << index
<< ") must be < getInstanceCount() ("<< mInstanceCount << ").";
return mLocalTransforms[index];
}
void FInstanceBuffer::prepare(FEngine& engine, math::mat4f const& rootTransform,
const PerRenderableData& ubo) {
DriverApi& driver = engine.getDriverApi();
void FInstanceBuffer::prepare(
BufferObjectHandle ubh,
PerRenderableData* const UTILS_RESTRICT buffer, uint32_t const offset, uint32_t const count,
math::mat4f const& rootTransform, PerRenderableData const& ubo) {
// there is a precondition check for this, so this assert really should never trigger
assert_invariant(count <= mInstanceCount);
for (size_t i = 0, c = count; i < c; i++) {
// TODO: allocate this staging buffer from a pool.
constexpr uint32_t stagingBufferSize = sizeof(PerRenderableUib);
PerRenderableData* stagingBuffer = static_cast<PerRenderableData*>(malloc(stagingBufferSize));
// TODO: consider using JobSystem to parallelize this.
for (size_t i = 0, c = mInstanceCount; i < c; i++) {
stagingBuffer[i] = ubo;
math::mat4f const model = rootTransform * mLocalTransforms[i];
stagingBuffer[i].worldFromModelMatrix = model;
math::mat3f const m = math::mat3f::getTransformForNormals(model.upperLeft());
buffer[offset + i] = ubo;
buffer[offset + i].worldFromModelMatrix = model;
buffer[offset + i].worldFromModelNormalMatrix = math::prescaleForNormals(m);
stagingBuffer[i].worldFromModelNormalMatrix = math::prescaleForNormals(m);
}
mHandle = ubh;
mOffset = offset * sizeof(PerRenderableData);
driver.updateBufferObject(mHandle, {
stagingBuffer, stagingBufferSize,
+[](void* buffer, size_t, void*) {
free(buffer);
}
}, 0);
}
} // namespace filament
+1 -9
View File
@@ -29,7 +29,6 @@
#include <utils/FixedCapacityVector.h>
#include <cstddef>
#include <cstdint>
namespace filament {
@@ -49,17 +48,11 @@ public:
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset);
math::mat4f const& getLocalTransform(size_t index) const noexcept;
void prepare(
backend::BufferObjectHandle ubh,
PerRenderableData* buffer, uint32_t offset, uint32_t count,
math::mat4f const& rootTransform, PerRenderableData const& ubo);
void prepare(FEngine& engine, math::mat4f const& rootTransform, const PerRenderableData& ubo);
utils::CString const& getName() const noexcept { return mName; }
backend::BufferObjectHandle getHandle() const noexcept { return mHandle; }
uint32_t getOffset() const noexcept { return mOffset; }
private:
friend class RenderableManager;
@@ -68,7 +61,6 @@ private:
utils::CString mName;
size_t mInstanceCount;
backend::BufferObjectHandle mHandle;
uint32_t mOffset = 0;
};
FILAMENT_DOWNCAST(InstanceBuffer)
+102 -41
View File
@@ -86,9 +86,9 @@ static std::unique_ptr<MaterialParser> createParser(Backend const backend,
MaterialParser::ParseResult const materialResult = materialParser->parse();
if (UTILS_UNLIKELY(materialResult == MaterialParser::ParseResult::ERROR_MISSING_BACKEND)) {
CString languageNames;
std::string languageNames;
for (auto it = languages.begin(); it != languages.end(); ++it) {
languageNames.append(CString{shaderLanguageToString(*it)});
languageNames.append(shaderLanguageToString(*it));
if (std::next(it) != languages.end()) {
languageNames.append(", ");
}
@@ -364,8 +364,24 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder,
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processMutableSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDescriptorSets(engine, parser);
switch (mMaterialDomain) {
case filament::MaterialDomain::SURFACE:
mVariantBits = VARIANT_BITS;
break;
case filament::MaterialDomain::POST_PROCESS:
mVariantBits = POST_PROCESS_VARIANT_BITS;
break;
case filament::MaterialDomain::COMPUTE:
mVariantBits = 0;
break;
}
mCachedPrograms = FixedCapacityVector<backend::Handle<backend::HwProgram>>(
1 << (mVariantBits + mMaterialMutableConstants.size()));
precacheDepthVariants(engine);
#if FILAMENT_ENABLE_MATDBG
@@ -466,13 +482,17 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
UserVariantFilterMask const variantFilter =
~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
int mutableConstantVariations = 1 << mMaterialMutableConstants.size();
if (UTILS_LIKELY(mEngine.getDriverApi().isParallelShaderCompileSupported())) {
auto const& variants = isVariantLit() ?
VariantUtils::getLitVariants() : VariantUtils::getUnlitVariants();
for (auto const variant: variants) {
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
if (hasVariant(variant)) {
prepareProgram(variant, priority);
for (int spec = 0; spec < mutableConstantVariations; spec++) {
prepareProgram(variant, Program::MutableSpecConstantsInfo(spec), priority);
}
}
}
}
@@ -553,14 +573,15 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
}
void FMaterial::prepareProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
assert_invariant(mEngine.hasFeatureLevel(mFeatureLevel));
switch (getMaterialDomain()) {
case MaterialDomain::SURFACE:
getSurfaceProgramSlow(variant, priorityQueue);
getSurfaceProgramSlow(variant, mutableSpecConstants, priorityQueue);
break;
case MaterialDomain::POST_PROCESS:
getPostProcessProgramSlow(variant, priorityQueue);
getPostProcessProgramSlow(variant, mutableSpecConstants, priorityQueue);
break;
case MaterialDomain::COMPUTE:
// TODO: implement MaterialDomain::COMPUTE
@@ -569,6 +590,7 @@ void FMaterial::prepareProgramSlow(Variant const variant,
}
void FMaterial::getSurfaceProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue const priorityQueue) const noexcept {
// filterVariant() has already been applied in generateCommands(), shouldn't be needed here
// if we're unlit, we don't have any bits that correspond to lit materials
@@ -579,25 +601,25 @@ void FMaterial::getSurfaceProgramSlow(Variant const variant,
Variant const vertexVariant = Variant::filterVariantVertex(variant);
Variant const fragmentVariant = Variant::filterVariantFragment(variant);
Program pb{ getProgramWithVariants(variant, vertexVariant, fragmentVariant) };
Program pb{ getProgramWithVariants(variant, vertexVariant, fragmentVariant, mutableSpecConstants) };
pb.priorityQueue(priorityQueue);
pb.multiview(
mEngine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW &&
Variant::isStereoVariant(variant));
createAndCacheProgram(std::move(pb), variant);
createAndCacheProgram(std::move(pb), variant, mutableSpecConstants);
}
void FMaterial::getPostProcessProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue const priorityQueue) const noexcept {
Program pb{ getProgramWithVariants(variant, variant, variant) };
Program pb{ getProgramWithVariants(variant, variant, variant, mutableSpecConstants) };
pb.priorityQueue(priorityQueue);
createAndCacheProgram(std::move(pb), variant);
createAndCacheProgram(std::move(pb), variant, mutableSpecConstants);
}
Program FMaterial::getProgramWithVariants(
Variant variant,
Variant vertexVariant,
Variant fragmentVariant) const {
Program FMaterial::getProgramWithVariants(Variant variant,
Variant vertexVariant, Variant fragmentVariant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const {
FEngine const& engine = mEngine;
const ShaderModel sm = engine.getShaderModel();
const bool isNoop = engine.getBackend() == Backend::NOOP;
@@ -658,45 +680,53 @@ Program FMaterial::getProgramWithVariants(
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_RENDERABLE]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_MATERIAL,
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_MATERIAL]);
program.specializationConstants(mSpecializationConstants);
program.specializationConstants(mSpecializationConstants,
CONFIG_MAX_RESERVED_SPEC_CONSTANTS + mMaterialConstants.size(), mutableSpecConstants);
program.pushConstants(ShaderStage::VERTEX, mPushConstants[uint8_t(ShaderStage::VERTEX)]);
program.pushConstants(ShaderStage::FRAGMENT, mPushConstants[uint8_t(ShaderStage::FRAGMENT)]);
program.cacheId(hash::combine(size_t(mCacheId), variant.key));
program.cacheId(
hash::combine(size_t(mCacheId),
hash::combine(variant.key, mutableSpecConstants.getValue())));
return program;
}
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const noexcept {
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant,
Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept {
FEngine const& engine = mEngine;
DriverApi& driverApi = mEngine.getDriverApi();
bool const isShared = isSharedVariant(variant);
size_t const cacheIndex = getCachedProgramIndex(variant, mutableSpecConstants);
// Check if the default material has this program cached
if (isShared) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial) {
auto const program = pDefaultMaterial->mCachedPrograms[variant.key];
auto const program = pDefaultMaterial->mCachedPrograms[cacheIndex];
if (program) {
mCachedPrograms[variant.key] = program;
mCachedPrograms[cacheIndex] = program;
return;
}
}
}
auto const program = driverApi.createProgram(std::move(p), mName);
auto const program = driverApi.createProgram(std::move(p));
driverApi.setDebugTag(program.getId(), mName);
assert_invariant(program);
mCachedPrograms[variant.key] = program;
mCachedPrograms[cacheIndex] = program;
// If the default material doesn't already have this program cached, and all caching conditions
// are met (Surface Domain and no custom depth shader), cache it now.
// New Materials will inherit these program automatically.
if (isShared) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
pDefaultMaterial->mCachedPrograms[variant.key] = program;
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[cacheIndex]) {
// set the tag to the default material name
driverApi.setDebugTag(program.getId(), mName);
pDefaultMaterial->mCachedPrograms[cacheIndex] = program;
}
}
}
@@ -744,6 +774,14 @@ size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const n
return count;
}
std::optional<uint32_t> FMaterial::getMutableConstantId(std::string_view name) const noexcept {
auto const pos = mMutableSpecializationConstantsNameToIndex.find(name);
if (pos != mMutableSpecializationConstantsNameToIndex.end()) {
return pos->second;
}
return std::nullopt;
}
#if FILAMENT_ENABLE_MATDBG
// Swaps in an edited version of the original package that was used to create the material. The
@@ -802,7 +840,9 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pActiveVariants) {
#endif // FILAMENT_ENABLE_MATDBG
[[nodiscard]] Handle<HwProgram> FMaterial::getProgramWithMATDBG(Variant const variant) const noexcept {
[[nodiscard]] Handle<HwProgram> FMaterial::getProgramWithMATDBG(Variant const variant,
Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept {
size_t cacheIndex = getCachedProgramIndex(variant, mutableSpecConstants);
#if FILAMENT_ENABLE_MATDBG
assert_invariant((size_t)variant.key < VARIANT_COUNT);
std::unique_lock lock(mActiveProgramsLock);
@@ -817,13 +857,13 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pActiveVariants) {
lock.unlock();
if (isSharedVariant(variant)) {
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[variant.key]) {
return pDefaultMaterial->getProgram(variant);
if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[cacheIndex]) {
return pDefaultMaterial->getProgram(variant, mutableSpecConstants);
}
}
#endif
assert_invariant(mCachedPrograms[variant.key]);
return mCachedPrograms[variant.key];
assert_invariant(mCachedPrograms[cacheIndex]);
return mCachedPrograms[cacheIndex];
}
void FMaterial::destroyPrograms(FEngine& engine,
@@ -836,7 +876,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
case MaterialDomain::SURFACE: {
if (mIsDefaultMaterial || mHasCustomDepthShader) {
// default material, or we have custom depth shaders, we destroy all variants
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variants, and this generates traffic in the command queue.
@@ -854,7 +894,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
UTILS_UNUSED_IN_RELEASE
auto const UTILS_NULLABLE pDefaultMaterial = engine.getDefaultMaterial();
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
@@ -866,7 +906,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
// During Engine::shutdown, auto-cleanup destroys the
// default material first
assert_invariant(!pDefaultMaterial ||
pDefaultMaterial->mCachedPrograms[k]);
pDefaultMaterial->mCachedPrograms[k & (VARIANT_COUNT - 1)]);
// we don't own this variant, skip, but clear the entry.
cachedPrograms[k].clear();
continue;
@@ -880,7 +920,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
break;
}
case MaterialDomain::POST_PROCESS: {
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
@@ -892,8 +932,13 @@ void FMaterial::destroyPrograms(FEngine& engine,
break;
}
case MaterialDomain::COMPUTE: {
// Compute programs don't have variants
driverApi.destroyProgram(std::move(cachedPrograms[0]));
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
if (cachedPrograms[k]) {
driverApi.destroyProgram(std::move(cachedPrograms[k]));
}
}
break;
}
}
@@ -1051,9 +1096,6 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
int const maxFroxelBufferHeight =
int(Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()) / 16u);
int const froxelRecordBufferHeight =
int(Froxelizer::getFroxelRecordBufferByteCount(engine.getDriverApi()) / 16u);
bool const staticTextureWorkaround =
engine.getDriverApi().isWorkaroundNeeded(Workaround::METAL_STATIC_TEXTURE_TARGET_ERROR);
@@ -1070,9 +1112,6 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT,
int(maxFroxelBufferHeight) });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_FROXEL_RECORD_BUFFER_HEIGHT,
int(froxelRecordBufferHeight) });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP,
engine.debug.shadowmap.debug_directional_shadowmap });
@@ -1134,6 +1173,19 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
}
}
void FMaterial::processMutableSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* const parser) {
// Older materials won't have a mutable constants chunk, but that's okay.
parser->getMutableConstants(&mMaterialMutableConstants);
for (size_t i = 0, c = mMaterialMutableConstants.size(); i < c; i++) {
auto& item = mMaterialMutableConstants[i];
// the key can be a string_view because mMaterialMutableConstants owns the CString
std::string_view const key{ item.name.data(), item.name.size() };
mMutableSpecializationConstantsNameToIndex[key] = i;
mDefaultMutableSpecializationConstants.set(i, item.defaultValue);
}
}
void FMaterial::processPushConstants(FEngine&, MaterialParser const* parser) {
FixedCapacityVector<Program::PushConstant>& vertexConstants =
mPushConstants[uint8_t(ShaderStage::VERTEX)];
@@ -1189,7 +1241,9 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
}
assert_invariant(Variant::isValidDepthVariant(variant));
if (hasVariant(variant)) {
prepareProgram(variant, CompilerPriorityQueue::HIGH);
// The default material shouldn't ever have mutable spec constants.
prepareProgram(variant, Program::MutableSpecConstantsInfo(0),
CompilerPriorityQueue::HIGH);
}
}
return;
@@ -1202,9 +1256,16 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
assert_invariant(pDefaultMaterial);
auto const allDepthVariants = VariantUtils::getDepthVariants();
int mutableConstantVariations = 1 << mMaterialMutableConstants.size();
for (auto const variant: allDepthVariants) {
assert_invariant(Variant::isValidDepthVariant(variant));
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
size_t defaultCacheIndex = pDefaultMaterial->getCachedProgramIndex(variant,
Program::MutableSpecConstantsInfo(0));
for (int spec = 0; spec < mutableConstantVariations; spec++) {
size_t cacheIndex = getCachedProgramIndex(variant,
Program::MutableSpecConstantsInfo(spec));
mCachedPrograms[cacheIndex] = pDefaultMaterial->mCachedPrograms[defaultCacheIndex];
}
}
}
}

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