Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84cecd334b | ||
|
|
bb6ebd3aea |
+1
-10
@@ -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.
|
||||
|
||||
@@ -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**]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+13
@@ -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);
|
||||
|
||||
|
||||
-9
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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', '~> 1.64.1'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.64.0'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"> </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"> </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"> </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 1.18 </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);">✒</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 1.18 </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);">✒</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">
|
||||
|
||||
@@ -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 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 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 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 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"> </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×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×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×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×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×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×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×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×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> "parameters": [
|
||||
<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 1.18 </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);">✒</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 1.18 </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);">✒</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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 > About Phone and tap the Build number 7 times). You need to go to
|
||||
Settings > System > 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 > System > 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 > 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
|
||||
</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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -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
|
||||
|
||||
|
||||
@@ -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)_
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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, ¤tPipeline, sizeof(PipelineState)) != 0)) {
|
||||
currentPipeline = pipeline;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user