Compare commits

..
Author SHA1 Message Date
Eliza Velasquez 84cecd334b materials: fix mutable spec constants nvidia bug
It turns out that I didn't understand how `FixedCapacityVector` works.
2025-09-03 18:13:09 -07:00
Eliza Velasquez bb6ebd3aea materials: reintroduce mutable spec constants
This change apparently breaks nvidia, still working on it.
2025-08-27 13:27:39 -07:00
247 changed files with 11927 additions and 5371 deletions
+1 -4
View File
@@ -8,7 +8,7 @@ runs:
uses: actions/cache@v3
id: cache-vulkan-sdk
with:
path: ~/VulkanSDK
path: ${{ runner.homedir }}/VulkanSDK
key: vulkansdk-${{ env.GITHUB_VULKANSDK_VERSION }}-2-${{ runner.os }}
- name: Download Vulkan SDK
if: steps.cache-vulkan-sdk.outputs.cache-hit != 'true'
@@ -21,9 +21,6 @@ runs:
run: |
source ${{ github.workspace }}/build/common/get-vulkan-sdk.sh
unpack_vulkan_installer
shell: bash
- name: Run Vulkan SDK setup
run: |
pushd .
cd ~/VulkanSDK/${GITHUB_VULKANSDK_VERSION}
sudo ./install_vulkan.py
+1 -1
View File
@@ -14,7 +14,7 @@ runs:
id: brew-cache
uses: actions/cache@v4 # Use a specific version
with:
path: ~/Library/Caches/Homebrew
path: $HOME/Library/Caches/Homebrew
key: ${{ runner.os }}-brew-20250424
- name: Install Mac Prerequisites
shell: bash
+1 -10
View File
@@ -532,15 +532,6 @@ if (FILAMENT_SUPPORTS_OPENGL)
add_definitions(-DFILAMENT_SUPPORTS_OPENGL)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
option(FILAMENT_ENABLE_PERFETTO "Enable perfetto SDK on Android" OFF)
else()
option(FILAMENT_ENABLE_PERFETTO "Enable perfetto SDK on Android" ON)
endif()
if (FILAMENT_ENABLE_PERFETTO)
add_definitions(-DFILAMENT_ENABLE_PERFETTO)
endif()
# By default, build with Vulkan support on desktop platforms, although clients must request to use
# it at run time.
if (WIN32 OR WEBGL OR IOS)
@@ -642,7 +633,7 @@ endif()
# With WebGPU, Tint does not support ClipDistance which is used in Stereo. Mentioned in comment
# https://github.com/google/dawn/blob/855d17b08abdf02f9142bf5a8f14d0ea088810a4/src/tint/lang/spirv/reader/ast_parser/function.cc#L4434
if (FILAMENT_SUPPORTS_WEBGPU)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=stereo)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=skinning,stereo)
endif()
# Disable ESSL 1.0 code generation.
+3
View File
@@ -7,3 +7,6 @@ We are chaning the way Vulkan buffers are handled. We need to switch over to a m
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
- materials: new mutable specialization constants feature. See the [materials documentation](https://google.github.io/filament/Materials.html) for details. [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.65.0'
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.0'
pod 'Filament', '~> 1.64.0'
```
## Documentation
-12
View File
@@ -7,18 +7,6 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.65.1
- `setFrameScheduledCallback` now works on all backends (frame presentation scheduling is still only
available on Metal). Non-Metal backends can use the callback to be notified when Filament has
finished processing a frame on the CPU.
- materials: added `getEyeFromViewMatrix()` for vertex shader [⚠️ **Recompile Materials**]
- matc: make `--workarounds=none` the default [**Recompile Materials to take effect**]
## v1.65.0
lighting: the intermediate froxel record buffer is now dynamically sized [⚠️ **New Material Version**]
## v1.64.1
- Update CMake minimum version to 3.22.1
-2
View File
@@ -178,8 +178,6 @@ nexusPublishing {
repositories {
sonatype {
stagingProfileId = '9a75a224a4f17b'
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
}
}
}
@@ -146,7 +146,7 @@ abstract class MaterialCompiler extends TaskWithBinary {
.gradleProperty("com.google.android.filament.include-webgpu")
.forUseAtConfigurationTime().present
if (include_webgpu) {
matcArgs += ['-a', 'webgpu', '--variant-filter=stereo']
matcArgs += ['-a', 'webgpu', '--variant-filter=skinning,stereo']
}
def mat_no_opt = providers
-2
View File
@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.19)
project(filamat-android)
set(CMAKE_CXX_STANDARD 20)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
+17 -19
View File
@@ -7,8 +7,6 @@ option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
add_library(filament STATIC IMPORTED)
@@ -132,14 +130,6 @@ add_library(filament-jni SHARED
../common/NioUtils.cpp
)
target_include_directories(filament-jni PRIVATE
..
${FILAMENT_DIR}/include
../../filament/backend/include
../../third_party/robin-map
../../third_party/perfetto
../../libs/utils/include)
# Ordering is significant in the following list. The PRIVATE qualifier prevents transitive deps.
target_link_libraries(filament-jni
PRIVATE filament-generatePrefilterMipmap
@@ -154,21 +144,29 @@ target_link_libraries(filament-jni
PRIVATE android
PRIVATE jnigraphics
PRIVATE utils
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE abseil # needed only when FILAMENT_USE_ABSEIL_LOGGING is defined
PRIVATE perfetto
PRIVATE abseil
PRIVATE zstd
# libgeometry is PUBLIC because gltfio uses it.
PUBLIC geometry
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
PRIVATE $<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:vkshaders>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:smol-v>
PRIVATE $<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn>
$<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:vkshaders>
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn>
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:smol-v>
)
target_include_directories(filament-jni PRIVATE
..
${FILAMENT_DIR}/include
../../filament/backend/include
../../third_party/robin-map
../../third_party/perfetto
../../libs/utils/include)
# Force a relink when the version script is changed:
set_target_properties(filament-jni PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT})
@@ -60,6 +60,14 @@ static void setParameter(JNIEnv* env, jlong nativeMaterialInstance, jstring name
env->ReleaseStringUTFChars(name_, name);
}
template<typename T>
static void setConstant(JNIEnv* env, jlong nativeMaterialInstance, jstring name_, T v) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
const char *name = env->GetStringUTFChars(name_, 0);
instance->setConstant(name, v);
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetParameterBool(JNIEnv *env, jclass,
@@ -264,6 +272,13 @@ Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
jlong nativeMaterialInstance, jstring name_, jboolean x) {
setConstant(env, nativeMaterialInstance, name_, bool(x));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetScissor(
@@ -450,13 +450,6 @@ Java_com_google_android_filament_RenderableManager_nGetPrimitiveCount(JNIEnv*, j
return (jint) rm->getPrimitiveCount((RenderableManager::Instance) i);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_RenderableManager_nGetInstanceCount(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i) {
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
return (jint) rm->getInstanceCount((RenderableManager::Instance) i);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nSetMaterialInstanceAt(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i, jint primitiveIndex, jlong nativeMaterialInstance) {
@@ -40,13 +40,6 @@ Java_com_google_android_filament_SwapChain_nIsSRGBSwapChainSupported(
return (jboolean)SwapChain::isSRGBSwapChainSupported(*engine);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_SwapChain_nIsMSAASwapChainSupported(
JNIEnv *, jclass, jlong nativeEngine, jint samples) {
Engine* engine = (Engine*) nativeEngine;
return (jboolean)SwapChain::isMSAASwapChainSupported(*engine, samples);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_SwapChain_nIsProtectedContentSupported(
JNIEnv *, jclass, jlong nativeEngine) {
@@ -402,6 +402,16 @@ public class MaterialInstance {
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
}
/**
* Sets the value of a bool constant.
*
* @param name the name of the material constant
* @param x the value of the material constant
*/
public void setConstant(@NonNull String name, boolean x) {
nSetConstantBool(getNativeObject(), name, x);
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
@@ -921,6 +931,9 @@ public class MaterialInstance {
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
private static native void nSetConstantBool(long nativeMaterialInstance,
@NonNull String name, boolean x);
private static native void nSetParameterTexture(long nativeMaterialInstance,
@NonNull String name, long nativeTexture, long sampler);
@@ -851,14 +851,6 @@ public class RenderableManager {
return nGetPrimitiveCount(mNativeObject, i);
}
/**
* Gets the immutable number of instances in the given renderable.
*/
@IntRange(from = 0)
public int getInstanceCount(@EntityInstance int i) {
return nGetInstanceCount(mNativeObject, i);
}
/**
* Changes the material instance binding for the given primitive.
*
@@ -1026,7 +1018,6 @@ public class RenderableManager {
private static native boolean nIsShadowReceiver(long nativeRenderableManager, int i);
private static native void nGetAxisAlignedBoundingBox(long nativeRenderableManager, int i, float[] center, float[] halfExtent);
private static native int nGetPrimitiveCount(long nativeRenderableManager, int i);
private static native int nGetInstanceCount(long nativeRenderableManager, int i);
private static native void nSetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex, long nativeMaterialInstance);
private static native void nClearMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
private static native long nGetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
@@ -97,19 +97,6 @@ public class SwapChain {
return nIsSRGBSwapChainSupported(engine.getNativeObject());
}
/**
* Return whether createSwapChain supports the CONFIG_MSAA_*_SAMPLES flag.
* The default implementation returns false.
*
* @param engine A reference to the filament Engine
* @param samples The number of samples
* @return true if CONFIG_MSAA_*_SAMPLES is supported, false otherwise.
* @see SwapChainFlags#CONFIG_MSAA_*_SAMPLES
*/
public static boolean isMSAASwapChainSupported(@NonNull Engine engine, int samples) {
return nIsMSAASwapChainSupported(engine.getNativeObject(), samples);
}
/**
* @return the native <code>Object</code> this <code>SwapChain</code> was created from or null
* for a headless SwapChain.
@@ -152,6 +139,5 @@ public class SwapChain {
private static native void nSetFrameCompletedCallback(long nativeSwapChain, Object handler, Runnable callback);
private static native boolean nIsSRGBSwapChainSupported(long nativeEngine);
private static native boolean nIsMSAASwapChainSupported(long nativeEngine, int samples);
private static native boolean nIsProtectedContentSupported(long nativeEngine);
}
@@ -92,15 +92,6 @@ public final class SwapChainFlags {
* The SwapChain contains protected content. Only supported when isProtectedContentSupported()
* is true.
*/
public static final long CONFIG_PROTECTED_CONTENT = 0x40;
/**
* Indicates that the SwapChain is configured to use Multi-Sample Anti-Aliasing (MSAA) with the
* given sample points within each pixel. Only supported when isMSAASwapChainSupported(4) is
* true.
*
* This is only supported by EGL(Android). Other GL platforms (GLX, WGL, etc) don't support it
* because the swapchain MSAA settings must be configured before window creation.
*/
public static final long CONFIG_MSAA_4_SAMPLES = 0x80;
public static final long CONFIG_PROTECTED_CONTENT = 0x40;
}
@@ -231,7 +231,7 @@ public class View {
*
* <p>
* The View does not take ownership of the Scene pointer. Before destroying a Camera, be sure
* to remove it from all associated Views. If the camera isn't set, Renderer::render() will result in a no-op.
* to remove it from all assoicated Views.
* </p>
*
* @see #getCamera
+11 -31
View File
@@ -1,14 +1,6 @@
cmake_minimum_required(VERSION 3.19)
project(filament-utils-android)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
set(IMAGEIO_DIR ../../libs/imageio)
@@ -38,16 +30,7 @@ add_library(iblprefilter STATIC IMPORTED)
set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
add_library(perfetto STATIC IMPORTED)
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
add_library(filament-utils-jni SHARED
@@ -70,25 +53,22 @@ add_library(filament-utils-jni SHARED
target_compile_definitions(filament-utils-jni PUBLIC IMAGEIO_LITE=1)
target_include_directories(filament-utils-jni PRIVATE
..
${FILAMENT_DIR}/include
..
../../filament/backend/include
${IMAGEIO_DIR}/include
../../libs/utils/include)
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT})
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.symbols)
# The ordering in the following list is important because CMake does not have dependency information.
target_link_libraries(filament-utils-jni
PRIVATE gltfio-jni
PRIVATE civetweb
PRIVATE camutils
PRIVATE iblprefilter
PRIVATE image
PRIVATE filament-jni
PRIVATE ktxreader
PRIVATE viewer
PRIVATE log
PRIVATE utils
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
gltfio-jni
civetweb
camutils
iblprefilter
image
ktxreader
viewer
)
+69 -37
View File
@@ -1,27 +1,20 @@
cmake_minimum_required(VERSION 3.19)
project(gltfio-android)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
set(CMAKE_CXX_STANDARD 20)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
set(GLTFIO_DIR ../../libs/gltfio)
set(DRACO_DIR ../../third_party/draco)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../filament-android ${CMAKE_CURRENT_BINARY_DIR}/filament-android)
add_library(gltfio_core STATIC IMPORTED)
set_target_properties(gltfio_core PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_core.a)
add_library(dracodec STATIC IMPORTED)
set_target_properties(dracodec PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libdracodec.a)
add_library(meshoptimizer STATIC IMPORTED)
set_target_properties(meshoptimizer PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libmeshoptimizer.a)
add_library(ktxreader STATIC IMPORTED)
set_target_properties(ktxreader PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libktxreader.a)
@@ -34,6 +27,10 @@ add_library(basis_transcoder STATIC IMPORTED)
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
add_library(zstd STATIC IMPORTED)
set_target_properties(zstd PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libzstd.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
@@ -50,11 +47,60 @@ add_library(uberarchive STATIC IMPORTED)
set_target_properties(uberarchive PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberarchive.a)
set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
set(GLTFIO_SRCS
${GLTFIO_DIR}/include/gltfio/Animator.h
${GLTFIO_DIR}/include/gltfio/AssetLoader.h
${GLTFIO_DIR}/include/gltfio/FilamentAsset.h
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
${GLTFIO_DIR}/include/gltfio/NodeManager.h
${GLTFIO_DIR}/include/gltfio/TrsTransformManager.h
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
${GLTFIO_DIR}/include/gltfio/math.h
${GLTFIO_DIR}/src/ArchiveCache.cpp
${GLTFIO_DIR}/src/ArchiveCache.h
${GLTFIO_DIR}/src/Animator.cpp
${GLTFIO_DIR}/src/AssetLoader.cpp
${GLTFIO_DIR}/src/DependencyGraph.cpp
${GLTFIO_DIR}/src/DependencyGraph.h
${GLTFIO_DIR}/src/DracoCache.cpp
${GLTFIO_DIR}/src/DracoCache.h
${GLTFIO_DIR}/src/FFilamentAsset.h
${GLTFIO_DIR}/src/FFilamentInstance.h
${GLTFIO_DIR}/src/FilamentAsset.cpp
${GLTFIO_DIR}/src/FilamentInstance.cpp
${GLTFIO_DIR}/src/FNodeManager.h
${GLTFIO_DIR}/src/FTrsTransformManager.h
${GLTFIO_DIR}/src/GltfEnums.h
${GLTFIO_DIR}/src/Ktx2Provider.cpp
${GLTFIO_DIR}/src/MaterialProvider.cpp
${GLTFIO_DIR}/src/NodeManager.cpp
${GLTFIO_DIR}/src/TrsTransformManager.cpp
${GLTFIO_DIR}/src/ResourceLoader.cpp
${GLTFIO_DIR}/src/StbProvider.cpp
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/TangentsJob.h
${GLTFIO_DIR}/src/UbershaderProvider.cpp
${GLTFIO_DIR}/src/Utility.cpp
${GLTFIO_DIR}/src/Utility.h
${GLTFIO_DIR}/src/Wireframe.cpp
${GLTFIO_DIR}/src/Wireframe.h
${GLTFIO_DIR}/src/downcast.h
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.cpp
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.h
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.cpp
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.h
${GLTFIO_DIR}/src/extended/TangentsJobExtended.cpp
${GLTFIO_DIR}/src/extended/TangentsJobExtended.h
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.cpp
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.h
src/main/cpp/Animator.cpp
src/main/cpp/AssetLoader.cpp
src/main/cpp/FilamentAsset.cpp
@@ -72,38 +118,24 @@ set(GLTFIO_SRCS
set(GLTFIO_INCLUDE_DIRS
..
${FILAMENT_DIR}/include
${FILAMENT_DIR}/backend/include
../../filament/backend/include
../../libs/gltfio/include
../../third_party/zstd/lib
../../third_party/cgltf
../../third_party/meshoptimizer/src
../../third_party/robin-map
../../third_party/stb
../../third_party/perfetto
../../libs/utils/include
../../libs/ktxreader/include
)
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
target_link_libraries(gltfio-jni filament-jni utils perfetto uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
target_link_libraries(gltfio-jni dracodec meshoptimizer)
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/tnt)
# Force a relink when the version script is changed:
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols;${VERSION_SCRIPT}")
# The ordering in the following list is important because CMake does not have dependency information.
target_link_libraries(gltfio-jni
PRIVATE gltfio_core
PRIVATE ktxreader
PUBLIC filament-jni
PRIVATE stb
PRIVATE basis_transcoder
PRIVATE uberarchive
PRIVATE dracodec
PRIVATE utils
PRIVATE uberzlib
PRIVATE perfetto # needed only when FILAMENT_ENABLE_PERFETTO is defined
PRIVATE log # needed only when perfetto above is used
)
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.65.0
VERSION_NAME=1.64.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -8
View File
@@ -75,8 +75,6 @@ function print_help {
echo " -S type"
echo " Enable stereoscopic rendering where type is one of [instanced|multiview]. This is only"
echo " meant for building the samples."
echo " -P"
echo " Enable perfetto traces on Android. Disabled by default on the Release build, enabled otherwise."
echo ""
echo "Build types:"
echo " release"
@@ -206,7 +204,6 @@ MATOPT_GRADLE_OPTION=""
ASAN_UBSAN_OPTION=""
COVERAGE_OPTION=""
ENABLE_PERFETTO=""
BACKEND_DEBUG_FLAG_OPTION=""
@@ -416,7 +413,6 @@ function build_android_target {
${WEBGPU_OPTION} \
${BACKEND_DEBUG_FLAG_OPTION} \
${STEREOSCOPIC_OPTION} \
${ENABLE_PERFETTO} \
../..
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
../../compile_commands.json
@@ -810,7 +806,7 @@ function check_debug_release_build {
pushd "$(dirname "$0")" > /dev/null
while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:P" opt; do
while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:" opt; do
case ${opt} in
h)
print_help
@@ -958,9 +954,6 @@ while getopts ":hacCfgimp:q:uvWslwedtk:bVx:S:X:P" opt; do
V) COVERAGE_OPTION="-DFILAMENT_ENABLE_COVERAGE=ON"
echo "Enabled coverage"
;;
P) ENABLE_PERFETTO="-DFILAMENT_ENABLE_PERFETTO=ON"
echo "Enabled perfetto"
;;
x) BACKEND_DEBUG_FLAG_OPTION="-DFILAMENT_BACKEND_DEBUG_FLAG=${OPTARG}"
;;
S) case $(echo "${OPTARG}" | tr '[:upper:]' '[:lower:]') in
@@ -1,349 +0,0 @@
#!/usr/bin/env python3
# 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.
"""
This script automates the process of closing a Sonatype OSSRH staging repository.
To run the script:
python3 ./close-sonatype-staging-repository.py
To run the embedded unit tests:
python3 ./close-sonatype-staging-repository.py test
"""
import sys
import os
import base64
import json
import pathlib
import unittest
import io
from unittest import mock
import urllib.request
import urllib.error
PROPERTIES_PATH = pathlib.Path.home() / ".gradle" / "gradle.properties"
API_BASE_URL = "https://ossrh-staging-api.central.sonatype.com/manual"
def get_gradle_credentials(file_path: pathlib.Path) -> (str, str):
"""
Reads sonatypeUsername and sonatypePassword from the properties file.
"""
if not file_path.exists():
print(f"Error: Properties file not found at {file_path}", file=sys.stderr)
sys.exit(1)
username = None
password = None
try:
with open(file_path, 'r') as f:
for line in f:
line = line.strip()
# Ignore blank lines and comments
if not line or line.startswith("#"):
continue
if line.startswith("sonatypeUsername="):
username = line.split("=", 1)[1].strip()
elif line.startswith("sonatypePassword="):
password = line.split("=", 1)[1].strip()
if not username or not password:
print(f"Error: 'sonatypeUsername' or 'sonatypePassword' not found in {file_path}", file=sys.stderr)
sys.exit(1)
return username, password
except Exception as e:
print(f"Error reading properties file: {e}", file=sys.stderr)
sys.exit(1)
def generate_auth_token(username: str, password: str) -> str:
"""
Generates a Base64 encoded auth token from username and password.
"""
auth_string = f"{username}:{password}"
auth_bytes = auth_string.encode('utf-8')
token_bytes = base64.b64encode(auth_bytes)
return token_bytes.decode('utf-8')
def find_staging_repository(token: str) -> str:
"""
Finds the 'open' staging repository key from the Sonatype API.
"""
print("Searching for staging repository...")
url = f"{API_BASE_URL}/search/repositories"
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json"
}
req = urllib.request.Request(url, headers=headers, method="GET")
try:
with urllib.request.urlopen(req) as response:
response_body = response.read().decode('utf-8')
data = json.loads(response_body)
repositories = data.get("repositories", [])
open_repositories = list(filter(lambda repo: repo.get("state") == "open", repositories))
if len(open_repositories) == 0:
print("Error: No 'open' staging repositories found.", file=sys.stderr)
sys.exit(1)
if len(open_repositories) > 1:
print(f"Error: Expected 1 'open' repository, but found {len(repositories)}.", file=sys.stderr)
sys.exit(1)
repo_key = open_repositories[0].get("key")
if not repo_key:
print("Error: Repository found, but it has no 'key'.", file=sys.stderr)
sys.exit(1)
return repo_key
except urllib.error.HTTPError as e:
# Handle HTTP errors (e.g., 401 Unauthorized, 404 Not Found, 500 Server Error)
print(f"Error during repository search: HTTP {e.code} {e.reason}", file=sys.stderr)
try:
# Try to read the error response body for more context
error_body = e.read().decode('utf-8')
print(f"Response body: {error_body}", file=sys.stderr)
except Exception:
pass # Ignore if we can't read the body
sys.exit(1)
except urllib.error.URLError as e:
# Handle network errors (e.g., connection refused)
print(f"Error during repository search: {e.reason}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError:
print("Error: Failed to decode JSON response from server.", file=sys.stderr)
sys.exit(1)
def close_staging_repository(token: str, repo_key: str):
"""
Closes (promotes) the staging repository with the given key.
"""
print(f"Attempting to close staging repository: {repo_key}")
url = f"{API_BASE_URL}/upload/repository/{repo_key}"
headers = {"Authorization": f"Bearer {token}"}
req = urllib.request.Request(url, headers=headers, method="POST")
try:
with urllib.request.urlopen(req) as response:
print(f"Successfully submitted request. Server responded with: {response.status} {response.reason}")
print("It may take a few moments to process.")
except urllib.error.HTTPError as e:
print(f"Error closing repository: HTTP {e.code} {e.reason}", file=sys.stderr)
try:
error_body = e.read().decode('utf-8')
print(f"Response body: {error_body}", file=sys.stderr)
except Exception:
pass
sys.exit(1)
except urllib.error.URLError as e:
print(f"Error closing repository: {e.reason}", file=sys.stderr)
sys.exit(1)
def main():
username, password = get_gradle_credentials(PROPERTIES_PATH)
token = generate_auth_token(username, password)
print("Successfully generated auth token.")
repo_key = find_staging_repository(token)
print(f"Found staging repository: {repo_key}")
close_staging_repository(token, repo_key)
print("\nScript completed successfully.")
# --- Unit Tests ---
class TestSonatypeScript(unittest.TestCase):
@mock.patch('pathlib.Path.exists', return_value=True)
@mock.patch('builtins.open', new_callable=mock.mock_open,
read_data="# This is a comment\nsonatypeUsername=testuser\n\nsonatypePassword=testpass\nother=data")
def test_get_gradle_credentials_success(self, mock_file, mock_exists):
"""Tests successful credential parsing, ignoring comments."""
user, pw = get_gradle_credentials(pathlib.Path("/fake/path"))
self.assertEqual(user, "testuser")
self.assertEqual(pw, "testpass")
@mock.patch('pathlib.Path.exists', return_value=False)
def test_get_gradle_credentials_no_file(self, mock_exists):
"""Tests error exit when file is missing."""
with self.assertRaises(SystemExit) as cm:
get_gradle_credentials(pathlib.Path("/fake/path"))
@mock.patch('pathlib.Path.exists', return_value=True)
@mock.patch('builtins.open', new_callable=mock.mock_open, read_data="# Only comments\nsonatypeUsername=testuser")
def test_get_gradle_credentials_missing_key(self, mock_file, mock_exists):
"""Tests error exit when a key is missing."""
with self.assertRaises(SystemExit) as cm:
get_gradle_credentials(pathlib.Path("/fake/path"))
def test_generate_auth_token(self):
"""Tests the Base64 token encoding."""
token = generate_auth_token("foobar", "abc123")
# echo -n "foobar:abc123" | base64
self.assertEqual(token, "Zm9vYmFyOmFiYzEyMw==")
@mock.patch('urllib.request.urlopen')
def test_find_repository_success(self, mock_urlopen):
"""Tests finding exactly one open repository."""
mock_response = mock.Mock()
mock_response.status = 200
mock_response.reason = "OK"
mock_response.read.return_value = json.dumps({
"repositories": [{"key": "test-repo-key-123", "state": "open"}]
}).encode('utf-8')
mock_urlopen.return_value.__enter__.return_value = mock_response
key = find_staging_repository("fake-token")
self.assertEqual(key, "test-repo-key-123")
@mock.patch('urllib.request.urlopen')
def test_find_repository_success(self, mock_urlopen):
"""Tests finding exactly one open repository."""
mock_response = mock.Mock()
mock_response.status = 200
mock_response.reason = "OK"
mock_response.read.return_value = json.dumps({
"repositories": [{"key": "test-repo-key-123", "state": "open"}, {"key": "test-repo-key-456", "state": "closed"}]
}).encode('utf-8')
mock_urlopen.return_value.__enter__.return_value = mock_response
key = find_staging_repository("fake-token")
self.assertEqual(key, "test-repo-key-123")
@mock.patch('urllib.request.urlopen')
def test_find_repository_success(self, mock_urlopen):
"""Tests error exit when only a closed repository is found."""
mock_response = mock.Mock()
mock_response.status = 200
mock_response.reason = "OK"
mock_response.read.return_value = json.dumps({
"repositories": [{"key": "test-repo-key-123", "state": "closed"}]
}).encode('utf-8')
mock_urlopen.return_value.__enter__.return_value = mock_response
with self.assertRaises(SystemExit) as cm:
key = find_staging_repository("fake-token")
@mock.patch('urllib.request.urlopen')
def test_find_repository_not_found(self, mock_urlopen):
"""Tests error exit when zero repositories are found."""
mock_response = mock.Mock()
mock_response.status = 200
mock_response.read.return_value = json.dumps({"repositories": []}).encode('utf-8')
mock_urlopen.return_value.__enter__.return_value = mock_response
with self.assertRaises(SystemExit) as cm:
find_staging_repository("fake-token")
@mock.patch('urllib.request.urlopen')
def test_find_repository_too_many(self, mock_urlopen):
"""Tests error exit when multiple open repositories are found."""
mock_response = mock.Mock()
mock_response.status = 200
mock_response.read.return_value = json.dumps({
"repositories": [{"key": "key1", "state": "open"}, {"key": "key2", "state": "open"}]
}).encode('utf-8')
mock_urlopen.return_value.__enter__.return_value = mock_response
with self.assertRaises(SystemExit) as cm:
find_staging_repository("fake-token")
@mock.patch('urllib.request.urlopen')
def test_find_repository_http_error(self, mock_urlopen):
"""Tests error exit on a network HTTP error."""
# Mock an HTTPError
mock_urlopen.side_effect = urllib.error.HTTPError(
url='http://fake.com',
code=401,
msg="Unauthorized",
hdrs={},
fp=io.BytesIO(b'{"error":"bad token"}')
)
with self.assertRaises(SystemExit) as cm:
find_staging_repository("fake-token")
@mock.patch('urllib.request.urlopen')
def test_close_repository_success(self, mock_urlopen):
"""Tests successful repository close."""
mock_response = mock.Mock()
mock_response.status = 202 # 202 Accepted is a common response for POST
mock_response.reason = "Accepted"
mock_urlopen.return_value.__enter__.return_value = mock_response
close_staging_repository("fake-token", "test-repo-key")
# Check that the request object was created correctly
called_request = mock_urlopen.call_args[0][0]
self.assertEqual(called_request.full_url, f"{API_BASE_URL}/upload/repository/test-repo-key")
self.assertEqual(called_request.method, "POST")
self.assertEqual(called_request.headers["Authorization"], "Bearer fake-token")
@mock.patch('urllib.request.urlopen')
def test_close_repository_http_error(self, mock_urlopen):
"""Tests error exit on close network failure."""
mock_urlopen.side_effect = urllib.error.HTTPError(
url='http://fake.com',
code=500,
msg="Server Error",
hdrs={},
fp=io.BytesIO(b'{"error":"failed to close"}')
)
with self.assertRaises(SystemExit) as cm:
close_staging_repository("fake-token", "test-repo-key")
def run_unit_tests():
"""
Configures and runs the unit tests.
"""
print("Running unit tests...")
# We replace sys.argv to prevent unittest.main from
# trying to parse the 'test' argument.
original_argv = sys.argv
sys.argv = [original_argv[0]] # Keep only the script name
unittest.main()
sys.argv = original_argv # Restore original args
if __name__ == '__main__':
# Check if the user wants to run tests
if len(sys.argv) > 1 and sys.argv[1].lower() == 'test':
run_unit_tests()
else:
# Run the main script logic
main()
+22 -25
View File
@@ -212,7 +212,7 @@ when using textures.
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by `baseColor`).
(reflected light takes on the color of the surfaced as defined by `baseColor`).
The effect of `metallic` is shown in figure [metallicProperty] (click on the image to see a
larger version).
@@ -248,7 +248,7 @@ The effect of `roughness` on metallic surfaces is shown in figure [roughnessCond
When refraction through an object is enabled (using a `refractonType` of `thin` or `solid`), the
`roughness` property will also affect the refractions, as shown in figure
[roughnessRefractionProperty] (click on the image to see a larger version).
![Figure [roughnessRefractionProperty]: Refractive sphere with `roughness` varying from 0.0
(left) to 1.0 (right)](images/materials/refraction_roughness.png)
@@ -307,7 +307,7 @@ The sheen color controls the color appearance and strength of an optional sheen
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section [Cloth model] for more information about cloth and fabric materials.
The effect of `sheenColor` is shown in figure [materialSheenColor]
@@ -520,14 +520,14 @@ light to bend further away from the initial path.
Table [commonMatIOR] describes acceptable refractive indices for various types of materials.
Material | IOR
Material | IOR
--------------------------:|:-----------------
Air | 1.0
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
[Table [commonMatIOR]: Index of refraction of common materials]
The appearance of a refractive material will greatly depend on the `refractionType` and
@@ -995,10 +995,10 @@ Value
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
mobile), `low`, `medium`, `high`. The type must be one of the types described in
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
Type | Description
:----------------------|:---------------------------------
@@ -2476,17 +2476,14 @@ type aliases:
### Matrices
Name | Type | Description
:-----------------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getEyeFromViewMatrix()** | float4x4 | Matrix that converts from view space to eye space
**getEyeFromViewMatrix(int eyeIndex)** | float4x4 | Matrix that converts from view space to eye space for the eye referred to by eyeIndex
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getClipFromWorldMatrix(int eyeIndex)** | float4x4 | Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
### Frame constants
@@ -2642,7 +2639,7 @@ standard skybox material. It produces a list of 2 parameters, named `showSun` an
respectively a boolean and a cubemap texture.
```text
$ matc --reflect parameters filament/src/materials/skybox.mat
$ matc --reflect parameters filament/src/materials/skybox.mat
{
"parameters": [
{
@@ -2658,7 +2655,7 @@ $ matc --reflect parameters filament/src/materials/skybox.mat
}
]
}
```
```
### --variant-filter
-267
View File
@@ -1,267 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Maven Release - 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="maven-release"><a class="header" href="#maven-release">Maven Release</a></h1>
<h2 id="register-for-a-sonatype-account"><a class="header" href="#register-for-a-sonatype-account">Register for a Sonatype Account</a></h2>
<p>First, you'll need to register for a Sonatype account at the <a href="https://central.sonatype.org/register/central-portal/">Central
Portal</a>.</p>
<p>To publish under the <code>com.google.android</code> namespace, you'll also need to email
<code>central-support@sonatype.com</code> with your account information to request access.</p>
<p>Then, generate a user token through the Sonatype website. Navigate to
<a href="https://central.sonatype.com/account">https://central.sonatype.com/account</a> and select <strong>Generate
User Token</strong>.</p>
<p>Finally, add the generated token credentials to <code>~/.gradle/gradle.properties</code>. (Note: these are
different from the credentials used to log into your Sonatype account):</p>
<pre><code class="language-gradle"># Generated Sonatype token
sonatypeUsername=&lt;username&gt;
sonatypePassword=&lt;password&gt;
</code></pre>
<hr />
<h2 id="signing-key"><a class="header" href="#signing-key">Signing Key</a></h2>
<p>All release artifacts must be signed. You'll need to create an OpenPGP key pair. See Gradle's
documentation on <a href="https://docs.gradle.org/current/userguide/signing_plugin.html#sec:signatory_credentials">Signatory
credentials</a>
for instructions.</p>
<p>Update <code>~/.gradle/gradle.properties</code> with your new key's credentials:</p>
<pre><code class="language-gradle">signing.keyId=&lt;key id&gt;
signing.password=&lt;key password&gt;
signing.secretKeyRingFile=&lt;secret key ring file&gt;
</code></pre>
<hr />
<h2 id="build-the-android-release"><a class="header" href="#build-the-android-release">Build the Android Release</a></h2>
<p>Make sure <code>JAVA_HOME</code> is set correctly. For example:</p>
<pre><code class="language-bash">export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home
./build.sh -C -i -p android release
</code></pre>
<hr />
<h2 id="publish-to-sonatype"><a class="header" href="#publish-to-sonatype">Publish to Sonatype</a></h2>
<h3 id="a-note-on-the-legacy-staging-service"><a class="header" href="#a-note-on-the-legacy-staging-service">A Note on the Legacy Staging Service</a></h3>
<p>Previously, Filament was published to Maven via OSSRH (Open Source Software Repository Hosting). In
2025, this service was <a href="https://central.sonatype.org/pages/ossrh-eol/">sunsetted</a>. Now, we use
Sonatype's <a href="https://central.sonatype.org/">Central Publisher Portal</a>.</p>
<p>The new Central Publisher Portal does not officially support Gradle. However, Sonatype provides a
staging API compatibility service, which works with Filament's Gradle setup.</p>
<hr />
<h3 id="1-upload-to-the-staging-api-compatibility-service"><a class="header" href="#1-upload-to-the-staging-api-compatibility-service">1. Upload to the Staging API Compatibility Service</a></h3>
<pre><code class="language-bash">cd android
./gradlew publishToSonatype
</code></pre>
<h3 id="2-move-the-repository-to-the-central-publisher-portal"><a class="header" href="#2-move-the-repository-to-the-central-publisher-portal">2. Move the Repository to the Central Publisher Portal</a></h3>
<p>We have a script to automate this. It reads the <code>sonatypeUsername</code> and <code>sonatypePassword</code> from your
<code>~/.gradle/gradle.properties</code> file.</p>
<pre><code class="language-bash">python3 build/common/close-sonatype-staging-repository.py
</code></pre>
<h3 id="3-publish-the-release-on-sonatype"><a class="header" href="#3-publish-the-release-on-sonatype">3. Publish the Release on Sonatype</a></h3>
<p>Navigate to <a href="https://central.sonatype.com/publishing/deployments">Maven Central Repository Deployments</a>.</p>
<p>Here, you should see a new deployment with a <strong>Validated</strong> status and all your artifacts listed. Click
the <strong>Publish</strong> button to publish the artifacts. It typically takes around 5 minutes after clicking
<strong>Publish</strong> for the artifacts to go live.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/windows_android.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="../dup/contributing.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="../build/windows_android.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="../dup/contributing.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>
+2 -2
View File
@@ -273,7 +273,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -287,7 +287,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../build/maven_release.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -209,7 +209,7 @@ as possible. The current external dependencies of the runtime library include:</
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../build/maven_release.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -223,7 +223,7 @@ as possible. The current external dependencies of the runtime library include:</
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../build/maven_release.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.65.0'
implementation 'com.google.android.filament:filament-android:1.64.0'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.65.0'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.64.0'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+1 -1
View File
@@ -162,7 +162,7 @@
<p>This tool makes it easy to analyze the composition of Android applications that use Filament.</p>
<ul>
<li>Filament materials are shown in the treemap if <code>resgen --json</code> was used in the build.</li>
<li>The input path can be a <code>.so</code> or <code>.a</code> file, a folder, or a zip archive (apk or aar).</li>
<li>The input path can be a so file, folder, or zip archive (apk or aar).</li>
<li>If the path is a zip or folder, interactively finds the file to analyze.</li>
<li>The generated web report is a self-contained HTML file.</li>
<li>Reports the gzipped size of all Filament materials.</li>
+4 -4
View File
@@ -178,9 +178,9 @@ content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5)
counter-increment: h6;margin-right:10px}
</style><style>.hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:#000;-webkit-text-size-adjust:none}.hljs-comment{color:#006a00}.hljs-keyword{color:#02E}.hljs-literal,.nginx .hljs-title{color:#aa0d91}.method,.hljs-list .hljs-title,.hljs-tag .hljs-title,.setting .hljs-value,.hljs-winutils,.tex .hljs-command,.http .hljs-title,.hljs-request,.hljs-status,.hljs-name{color:#008}.hljs-envvar,.tex .hljs-special{color:#660}.hljs-string{color:#c41a16}.hljs-tag .hljs-value,.hljs-cdata,.hljs-filter .hljs-argument,.hljs-attr_selector,.apache .hljs-cbracket,.hljs-date,.hljs-regexp{color:#080}.hljs-sub .hljs-identifier,.hljs-pi,.hljs-tag,.hljs-tag .hljs-keyword,.hljs-decorator,.ini .hljs-title,.hljs-shebang,.hljs-prompt,.hljs-hexcolor,.hljs-rule .hljs-value,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-number,.css .hljs-function,.hljs-function .hljs-title,.coffeescript .hljs-attribute{color:#A0C}.hljs-function .hljs-title{font-weight:bold;color:#000}.hljs-class .hljs-title,.smalltalk .hljs-class,.hljs-type,.hljs-typename,.hljs-tag .hljs-attribute,.hljs-doctype,.hljs-class .hljs-id,.hljs-built_in,.setting,.hljs-params,.clojure .hljs-attribute{color:#5c2699}.hljs-variable{color:#3f6e74}.css .hljs-tag,.hljs-rule .hljs-property,.hljs-pseudo,.hljs-subst{color:#000}.css .hljs-class,.css .hljs-id{color:#9b703f}.hljs-value .hljs-important{color:#ff7700;font-weight:bold}.hljs-rule .hljs-keyword{color:#c5af75}.hljs-annotation,.apache .hljs-sqbracket,.nginx .hljs-built_in{color:#9b859d}.hljs-preprocessor,.hljs-preprocessor *,.hljs-pragma{color:#643820}.tex .hljs-formula{background-color:#eee;font-style:italic}.diff .hljs-header,.hljs-chunk{color:#808080;font-weight:bold}.diff .hljs-change{background-color:#bccff9}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-comment .hljs-doctag{font-weight:bold}.method .hljs-id{color:#000}</style><style>div.title { padding-top: 40px; } div.afterTitles { height: 15px; }</style><meta charset="utf-8"></p>
<style>img { max-width: 100%; }</style>
<p><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{,\mathrm{#1}}$$
<script type="text/x-mathjax-config">MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "AMS"} } });</script><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{\,\mathrm{#1}}$$
</span>
<span class="md"><p><title>Physically Based Rendering in Filament</title><div class="title"> Physically Based Rendering in Filament </div></p>
<span class="md"><p><title>Physically Based Rendering in Filament</title><div class="title"> Physically Based Rendering in Filament </div>
<div class="afterTitles"></div>
</p><p>
</p>
@@ -2060,7 +2060,7 @@ In practice only 4 or 9 coefficients (i.e.: 2 or 3 bands) are enough for \(\cosT
In practice we pre-convolve \(\Lt\) with \(\cosTheta\) and pre-scale these coefficients by the basis scaling factors \(K_l^m\) so that the reconstruction code is as simple as possible in the shader:
</p><a class="target" name="listing_irradiancesh">&nbsp;</a><pre class="listing tilde"><code><span class="line"></span>vec3 irradianceSH(vec3 n) {
<span class="line"></span> // uniform vec3 sphericalHarmonics<span class="hljs-selector-attr">[9]</span>
<span class="line"></span> // We can <span class="hljs-selector-tag">use</span> only the first <span class="hljs-number">2</span> bands for better performance
<span class="line"></span> // We can use only the first <span class="hljs-number">2</span> bands for better performance
<span class="line"></span> return
<span class="line"></span> sphericalHarmonics<span class="hljs-selector-attr">[0]</span>
<span class="line"></span> + sphericalHarmonics<span class="hljs-selector-attr">[1]</span> * (n<span class="hljs-selector-class">.y</span>)
@@ -4395,7 +4395,7 @@ For Fast Realistic Image Display. <em class="asterisk">SIGGRAPH '00 Proceedings
</div><div class="bib">[<a class="target" name="citation-schlick94">&nbsp;</a><b>Schlick94</b>] Christophe Schlick. 1994. An Inexpensive BRDF Model for Physically-Based Rendering. <em class="asterisk">Computer Graphics Forum</em>, 13 (3), 233–246.
</div><div class="bib">[<a class="target" name="citation-walter07">&nbsp;</a><b>Walter07</b>] Bruce Walter et al. 2007. Microfacet Models for Refraction through Rough Surfaces. <em class="asterisk">Proceedings of the Eurographics Symposium on Rendering</em>.
</div>
</sample></float></sample></float></float></p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
</sample></float></sample></float></float></p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
+9 -12
View File
@@ -178,9 +178,9 @@ content:counter(h1) "."counter(h2) "."counter(h3) "."counter(h4) "."counter(h5)
counter-increment: h6;margin-right:10px}
</style><style>.hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:#000;-webkit-text-size-adjust:none}.hljs-comment{color:#006a00}.hljs-keyword{color:#02E}.hljs-literal,.nginx .hljs-title{color:#aa0d91}.method,.hljs-list .hljs-title,.hljs-tag .hljs-title,.setting .hljs-value,.hljs-winutils,.tex .hljs-command,.http .hljs-title,.hljs-request,.hljs-status,.hljs-name{color:#008}.hljs-envvar,.tex .hljs-special{color:#660}.hljs-string{color:#c41a16}.hljs-tag .hljs-value,.hljs-cdata,.hljs-filter .hljs-argument,.hljs-attr_selector,.apache .hljs-cbracket,.hljs-date,.hljs-regexp{color:#080}.hljs-sub .hljs-identifier,.hljs-pi,.hljs-tag,.hljs-tag .hljs-keyword,.hljs-decorator,.ini .hljs-title,.hljs-shebang,.hljs-prompt,.hljs-hexcolor,.hljs-rule .hljs-value,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-number,.css .hljs-function,.hljs-function .hljs-title,.coffeescript .hljs-attribute{color:#A0C}.hljs-function .hljs-title{font-weight:bold;color:#000}.hljs-class .hljs-title,.smalltalk .hljs-class,.hljs-type,.hljs-typename,.hljs-tag .hljs-attribute,.hljs-doctype,.hljs-class .hljs-id,.hljs-built_in,.setting,.hljs-params,.clojure .hljs-attribute{color:#5c2699}.hljs-variable{color:#3f6e74}.css .hljs-tag,.hljs-rule .hljs-property,.hljs-pseudo,.hljs-subst{color:#000}.css .hljs-class,.css .hljs-id{color:#9b703f}.hljs-value .hljs-important{color:#ff7700;font-weight:bold}.hljs-rule .hljs-keyword{color:#c5af75}.hljs-annotation,.apache .hljs-sqbracket,.nginx .hljs-built_in{color:#9b859d}.hljs-preprocessor,.hljs-preprocessor *,.hljs-pragma{color:#643820}.tex .hljs-formula{background-color:#eee;font-style:italic}.diff .hljs-header,.hljs-chunk{color:#808080;font-weight:bold}.diff .hljs-change{background-color:#bccff9}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-comment .hljs-doctag{font-weight:bold}.method .hljs-id{color:#000}</style><style>div.title { padding-top: 40px; } div.afterTitles { height: 15px; }</style><meta charset="utf-8"></p>
<style>img { max-width: 100%; }</style>
<p><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{,\mathrm{#1}}$$
<script type="text/x-mathjax-config">MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "AMS"} } });</script><span style="display:none">$$\newcommand{\n}{\hat{n}}\newcommand{\thetai}{\theta_\mathrm{i}}\newcommand{\thetao}{\theta_\mathrm{o}}\newcommand{\d}[1]{\mathrm{d}#1}\newcommand{\w}{\hat{\omega}}\newcommand{\wi}{\w_\mathrm{i}}\newcommand{\wo}{\w_\mathrm{o}}\newcommand{\wh}{\w_\mathrm{h}}\newcommand{\Li}{L_\mathrm{i}}\newcommand{\Lo}{L_\mathrm{o}}\newcommand{\Le}{L_\mathrm{e}}\newcommand{\Lr}{L_\mathrm{r}}\newcommand{\Lt}{L_\mathrm{t}}\newcommand{\O}{\mathrm{O}}\newcommand{\degrees}{{^{\large\circ}}}\newcommand{\T}{\mathsf{T}}\newcommand{\mathset}[1]{\mathbb{#1}}\newcommand{\Real}{\mathset{R}}\newcommand{\Integer}{\mathset{Z}}\newcommand{\Boolean}{\mathset{B}}\newcommand{\Complex}{\mathset{C}}\newcommand{\un}[1]{\,\mathrm{#1}}$$
</span>
<span class="md"><p><title>Filament Materials Guide</title><div class="title"> Filament Materials Guide </div></p>
<span class="md"><p><title>Filament Materials Guide</title><div class="title"> Filament Materials Guide </div>
<div class="afterTitles"></div>
</p><p>
</p>
@@ -504,7 +504,7 @@ when using textures.</p>
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by <code>baseColor</code>).
(reflected light takes on the color of the surfaced as defined by <code>baseColor</code>).
</p><p>
The effect of <code>metallic</code> is shown in <a href="#figure_metallicproperty" target="_self">figure&nbsp;1</a> (click on the image to see a
larger version).
@@ -597,7 +597,7 @@ indices.
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.</p>
</p><p>
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section <a href="#toc3.3" target="_self">3.3</a> for more information about cloth and fabric materials.
</p><p>
The effect of <code>sheenColor</code> is shown in <a href="#figure_materialsheencolor" target="_self">figure&nbsp;7</a>
@@ -1220,10 +1220,10 @@ non-shader data.</p>
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
<a href="#table_materialparamstypes" target="_self">table&nbsp;14</a>. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
</p></dd></dl><div class='table'>
<a class="target" name="table_materialparamstypes">&nbsp;</a><table class="table longtable"><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
<tr><td style="text-align:left"> bool </td><td style="text-align:left"> Single boolean </td></tr>
@@ -2361,10 +2361,7 @@ type aliases:</p>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view/eye space to world space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view/eye space to clip (NDC) space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getViewFromClipMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from clip (NDC) space to view/eye space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getEyeFromViewMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view space to eye space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getEyeFromViewMatrix(int eyeIndex)</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from view space to eye space for the eye referred to by eyeIndex </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromWorldMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from world to clip (NDC) space </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getClipFromWorldMatrix(int eyeIndex)</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex </td></tr>
<tr><td style="text-align:left"> <strong class="asterisk">getWorldFromClipMatrix()</strong> </td><td style="text-align:center"> float4&times;4 </td><td style="text-align:left"> Matrix that converts from clip (NDC) space to world space </td></tr>
</table></div>
</p>
@@ -2504,7 +2501,7 @@ a good compromise between runtime performance and size.</p>
metadata in JSON format. The example below prints out the list of parameters defined in Filament's
standard skybox material. It produces a list of 2 parameters, named <code>showSun</code> and <code>skybox</code>,
respectively a boolean and a cubemap texture.</p>
</p><pre class="listing backtick"><code><span class="line"></span>$ matc --reflect parameters filament/src/materials/skybox.mat
</p><pre class="listing backtick"><code><span class="line"></span>$ matc --reflect parameters filament/src/materials/skybox.mat
<span class="line"></span>{
<span class="line"></span> &quot;parameters&quot;: [
<span class="line"></span> {
@@ -2603,7 +2600,7 @@ Finally if <code>variantFilter</code> contains the <code>fog</code> filter, an e
</p><p>
Be aware that <code>external</code> samplers account for 2 regular samplers.</div>
</p><p>
</p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
</p></span><div id="mdContextMenu" style="visibility:hidden"></div><div class="markdeepFooter"><i>formatted by <a href="https://casual-effects.com/markdeep" style="color:#999">Markdeep&nbsp;1.18&nbsp;&nbsp;</a></i><div style="display:inline-block;font-size:13px;font-family:'Times New Roman',serif;vertical-align:middle;transform:translate(-3px,-1px)rotate(135deg);">&#x2712;</div></div><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
+2 -2
View File
@@ -250,7 +250,7 @@ execution profile data.</p>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/framegraph.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -264,7 +264,7 @@ execution profile data.</p>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/framegraph.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -331,7 +331,7 @@ nodes</li>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/performance_analysis.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/coverage.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -345,7 +345,7 @@ nodes</li>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/performance_analysis.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/coverage.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
-352
View File
@@ -1,352 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Performance analysis - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="performance-analysis"><a class="header" href="#performance-analysis">Performance Analysis</a></h1>
<h2 id="android"><a class="header" href="#android">Android</a></h2>
<h3 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h3>
<ul>
<li>Download and install Android GPU Inspector (AGI). See https://developer.android.com/agi.</li>
</ul>
<hr />
<h4 id="profiling"><a class="header" href="#profiling">Profiling</a></h4>
<ol>
<li>
<p>Before profiling the application or analyzing the performance in a consistent way, ideally
the <strong>GPU frequency on the target hardware should get locked</strong>. In order to do this, you need to do the following:</p>
<ol>
<li>Ensure your device is OEM unlocked. If your phone is carrier-locked, you may need
to wait a period, such as 60 or 90 days after activation to be eligible for unlocking.
Some phones don't support this at all. You will need to enable developer options
(e.g. Settings &gt; About Phone and tap the Build number 7 times). You need to go to
Settings &gt; System &gt; Developer options and toggle on "OEM unlocking".</li>
<li>Next, you need to unlock the phone. You will need to install Android SDK Platform
Tools on you computer, enable "USB debugging" in your phone's Settings &gt; System &gt; Developer options.</li>
<li>Connect the phone to the computer via a USB cable and run from the command line:
<pre><code class="language-shell">adb reboot bootloader
# once the phone is in bootloader mode, run the following to begin the unlocking
# process:
fastboot flashing unlock
</code></pre>
A warning will appear on your phone's screen. Use the volume buttons to navigate and
the power button to select the "Unlock the bootloader" option. The phone will perform
a factory data reset and reboot with an unlocked bootloader.</li>
<li>You would need to flash an image to the phone with root permissions, such as a *-userdebug or *-eng
build. One way to do this is with the <a href="https://flash.android.com/">Android Flash Tool</a>. Connect the
tool to your device and find a build to flash ending in <code>-userdebug</code> or <code>-eng</code>. Once you have that
selected run <code>Install build</code>.</li>
<li>Shell into your device as root and configure the gpu frequency to be locked, e.g.:
<pre><code class="language-shell">adb shell
su
# navigate to the system GPU directory. this varies on different phones. One phone might have
# it at /sys/class/kgsl/kgsl-3d0 and another might be in something similar, maybe with "mali" instead
# of "kgsl". At the time of writing this for the device at hand it was /sys/devices/platform/1f000000.mali
cd /sys/devices/platform/1f000000.mali
# get the current available GPU governors and frequencies.
# note that some systems may have these at gpu_available_governors and gpu_available_frequencies, but
# the system at the time of writing this had available_governors and available_frequences
cat available_governors
cat available_frequencies
# depending on the governors, you may want to set it prioritize performance over other things like
# battery. Some systems allow you to do this with something like (although, for the device used at the
# time of writing this did not have an equivalent option):
echo performance &gt; gpu_governor
# finally, lock your frequency in, usually to something high like 897 MHz. Some systems may have you
# pipe the value to gpu_min_freq and gpu_max_freq, but the system used at the time of writing this had:
echo 940000 &gt; hint_min_freq
echo 940000 &gt; hint_max_freq
# you can typically verify the GPU is running at that frequency consistently by running something like
# the following a few times over time, which should show the frequency you want to lock the device to:
cat cur_freq
</code></pre>
</li>
<li>You may need to re-apply the <code>hint_min_freq</code> just before starting the profiling trace and check before and after
that the frequency remained at the value expected. Some systems may adjust the frequency on you, but you
may want to ensure the frequency remains the same through the analysis.</li>
<li>The GPU frequency settings should be undone after restarting the device, but after you have done your app profiling,
you can revert the state of the device, such as the OS build image, back to the way you had it
initially, as needed.</li>
</ol>
</li>
<li>
<p>Build a release build of Filament with the applicable backend(s) enabled
<em>(+ any special flags for enabling sys strace. Nothing special is needed for Vulkan or WebGPU aside from
building a release build with no flags)</em> <em>(debug builds for this are useless)</em></p>
<pre><code class="language-shell"># the following command assumes you are in the root filament directory
# and ANDROID_HOME is exported (and possibly also CC and CXX on linux as needed)
#
# NOTE: to build with WebGPU support you need to explicitly include the -W flag
# (it doesn't get compiled in by default), e.g.:
# ./build.sh -W -p android,desktop -i release
#
# Note that you can speed this up a bit (and reduce disk space usage) by limiting the target to just
# the ABI you plan on testing with the -q flag, e.g. -q arm64-v8a. If you do this, you
# will need to update the android/gradle.properties file to specify the ABI(s) you are targeting
# with the com.google.android.filament.abis property.
# Thus, a build command that would target BOTH Vulkan AND WebGPU AND only target the ARM64 ABI would look something
# like:
# ./build.sh -W -q arm64-v8a -p android,desktop -i release
./build.sh -p android,desktop -i release
</code></pre>
</li>
<li>
<p>Connect your Android device to your computer via a USB cord with USB debugging enabled and configure
the system property to default to the desired backend, e.g.
<em>(to determine how these numbers map to the backends, see the <code>enum class Backend</code>
definition in <a href="../../../../filament/backend/include/backend/DriverEnums.h">filament/filament/backend/include/backend/DriverEnums.h</a>)</em>:</p>
<pre><code class="language-shell"># to set the backend to Vulkan:
adb shell setprop debug.filament.backend 2
# to set the backend to WebGPU:
adb shell setprop debug.filament.backend 4
# to view the current property:
adb shell getprop debug.filament.backend
</code></pre>
</li>
<li>
<p>Build and run a sample, e.g. sample-gltf-viewer, on your Android device
<em>(<a href="https://developer.android.com/studio">Android Studio</a> recommended)</em>.</p>
</li>
<li>
<p>Run <a href="https://developer.android.com/agi">AGI</a> and follow instructions to profile the app/system
with trace capture(s). See https://developer.android.com/agi/start for more details to
get started.</p>
<ul>
<li>We typically only run "Capture System Profiler trace" <em>(not necessarily "Capture Frame Profiler trace")</em></li>
<li>When configuring the trace:
<ul>
<li>For both the WebGPU and Vulkan backends configure the profiler for the Vulkan API
<em>(since WebGPU should be using Vulkan under the hood as well)</em></li>
<li>Running for ~1 seconds should suffice</li>
<li>Hit the "Configure" button in Trace objects, select "Switch to advanced mode" and add:
<pre><code>data_sources {
config {
name: "track_event"
track_event_config {
disabled_categories: "*"
enabled_categories: "filament/filament"
enabled_categories: "filament/jobsystem"
enabled_categories: "filament/gltfio"
}
}
}
</code></pre>
</li>
</ul>
</li>
<li>One you open the trace, zoom into a series of frames to get a sense of generally how long they typically take
<em>(use <code>W</code>, <code>S</code>, <code>A</code> and <code>D</code> keys and mouse wheel for navigation)</em> and find a representative one.
We are most interested in the performance of the
<code>FEngine::loop</code> thread, how long it takes, overlap in activities/processes/commands, reduction in queue submissions,
etc. Similarly, we can view GPU timeline as it relates to that. We want to see overlapping
shader invocations and non-interrupted fragment shader runs.</li>
</ul>
</li>
</ol>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/coverage.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/framegraph.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/coverage.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/framegraph.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+31 -27
View File
@@ -995,10 +995,10 @@ Value
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
mobile), `low`, `medium`, `high`. The type must be one of the types described in
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
table [materialParamsTypes]. For Android external textures, entries also have an optional
transformName parameter to specify the name of the material parameter that will be
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
this will always be identity.
this will always be identity.
Type | Description
:----------------------|:---------------------------------
@@ -1096,30 +1096,37 @@ Value
`bool` or `number`, depending on the `type` of the constant. The type must be one of the types
described in table [materialConstantsTypes].
Type | Description | Default
:----------------------|:-----------------------------------------|:------------------
int | A signed, 32 bit GLSL int | 0
float | A single-precision GLSL float | 0.0
bool | A GLSL bool | false
Constants may also be specified as mutable by setting the `mutable` property to `true`. Only
`bool` spec constants may be specified as mutable.
| Type | Description | Default | May be mutable? |
|:------|:------------------------------|:--------|-----------------|
| int | A signed, 32 bit GLSL int | | no |
| float | A single-precision GLSL float | 0.0 | no |
| bool | A GLSL bool | false | yes |
[Table [materialConstantsTypes]: Material constants types]
Description
: Lists the constant parameters accepted by your material. These constants can be set, or
"specialized", at runtime when loading a material package. Multiple materials can be loaded from
the same material package with differing constant parameter specializations. Once a material is
loaded from a material package, its constant parameters cannot be changed. Compared to regular
parameters, constant parameters allow the compiler to generate more efficient code. Access
constant parameters from the shader by prefixing the name with `materialConstant_`. For example,
a constant parameter named `myConstant` is accessed in the shader as
`materialConstant_myConstant`. If a constant parameter is not set at runtime, the default is
used.
the same material package with differing constant parameter specializations. If a constant
parameter is specialized as mutable, it may be changed at any time on a per-instance basis via
`MaterialInstance::setConstant(name, value)`. Otherwise, once a material is loaded from a
material package, its constant parameters cannot be changed.
Compared to regular parameters, constant parameters allow the compiler to generate more
efficient code. Access constant parameters from the shader by prefixing the name with
`materialConstant_`. For example, a constant parameter named `myConstant` is accessed in the
shader as `materialConstant_myConstant`. If a constant parameter is not set at runtime, the
default is used.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
constants : [
{
name : overrideAlpha,
type : bool
type : bool,
mutable : true,
},
{
name : customAlpha,
@@ -2476,17 +2483,14 @@ type aliases:
### Matrices
Name | Type | Description
:-----------------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getEyeFromViewMatrix()** | float4x4 | Matrix that converts from view space to eye space
**getEyeFromViewMatrix(int eyeIndex)** | float4x4 | Matrix that converts from view space to eye space for the eye referred to by eyeIndex
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getClipFromWorldMatrix(int eyeIndex)** | float4x4 | Matrix that converts from world to clip (NDC) space for the eye referred to by eyeIndex
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getViewFromWorldMatrix()** | float4x4 | Matrix that converts from world space to view/eye space
**getWorldFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to world space
**getClipFromViewMatrix()** | float4x4 | Matrix that converts from view/eye space to clip (NDC) space
**getViewFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to view/eye space
**getClipFromWorldMatrix()** | float4x4 | Matrix that converts from world to clip (NDC) space
**getWorldFromClipMatrix()** | float4x4 | Matrix that converts from clip (NDC) space to world space
### Frame constants
-2
View File
@@ -3,7 +3,6 @@
- [Introduction](./dup/intro.md)
- [Build](./dup/building.md)
- [Build for Android on Windows](./build/windows_android.md)
- [Maven Release](./build/maven_release.md)
- [Contribute](./dup/contributing.md)
- [Coding Style](./dup/code_style.md)
- [Core Concepts](./main/README.md)
@@ -25,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)
@@ -1,89 +0,0 @@
# Maven Release
## Register for a Sonatype Account
First, you'll need to register for a Sonatype account at the [Central
Portal](https://central.sonatype.org/register/central-portal/).
To publish under the `com.google.android` namespace, you'll also need to email
`central-support@sonatype.com` with your account information to request access.
Then, generate a user token through the Sonatype website. Navigate to
[https://central.sonatype.com/account](https://central.sonatype.com/account) and select **Generate
User Token**.
Finally, add the generated token credentials to `~/.gradle/gradle.properties`. (Note: these are
different from the credentials used to log into your Sonatype account):
```gradle
# Generated Sonatype token
sonatypeUsername=<username>
sonatypePassword=<password>
```
-----
## Signing Key
All release artifacts must be signed. You'll need to create an OpenPGP key pair. See Gradle's
documentation on [Signatory
credentials](https://docs.gradle.org/current/userguide/signing_plugin.html#sec:signatory_credentials)
for instructions.
Update `~/.gradle/gradle.properties` with your new key's credentials:
```gradle
signing.keyId=<key id>
signing.password=<key password>
signing.secretKeyRingFile=<secret key ring file>
```
-----
## Build the Android Release
Make sure `JAVA_HOME` is set correctly. For example:
```bash
export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home
./build.sh -C -i -p android release
```
-----
## Publish to Sonatype
### A Note on the Legacy Staging Service
Previously, Filament was published to Maven via OSSRH (Open Source Software Repository Hosting). In
2025, this service was [sunsetted](https://central.sonatype.org/pages/ossrh-eol/). Now, we use
Sonatype's [Central Publisher Portal](https://central.sonatype.org/).
The new Central Publisher Portal does not officially support Gradle. However, Sonatype provides a
staging API compatibility service, which works with Filament's Gradle setup.
-----
### 1\. Upload to the Staging API Compatibility Service
```bash
cd android
./gradlew publishToSonatype
```
### 2\. Move the Repository to the Central Publisher Portal
We have a script to automate this. It reads the `sonatypeUsername` and `sonatypePassword` from your
`~/.gradle/gradle.properties` file.
```bash
python3 build/common/close-sonatype-staging-repository.py
```
### 3\. Publish the Release on Sonatype
Navigate to [Maven Central Repository Deployments](https://central.sonatype.com/publishing/deployments).
Here, you should see a new deployment with a **Validated** status and all your artifacts listed. Click
the **Publish** button to publish the artifacts. It typically takes around 5 minutes after clicking
**Publish** for the artifacts to go live.
@@ -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)_
-3
View File
@@ -40,7 +40,6 @@ set(PUBLIC_HDRS
include/filament/Skybox.h
include/filament/Stream.h
include/filament/SwapChain.h
include/filament/Sync.h
include/filament/Texture.h
include/filament/TextureSampler.h
include/filament/ToneMapper.h
@@ -104,7 +103,6 @@ set(SRCS
src/Skybox.cpp
src/Stream.cpp
src/SwapChain.cpp
src/Sync.cpp
src/Texture.cpp
src/ToneMapper.cpp
src/TransformManager.cpp
@@ -134,7 +132,6 @@ set(SRCS
src/details/Skybox.cpp
src/details/Stream.cpp
src/details/SwapChain.cpp
src/details/Sync.cpp
src/details/Texture.cpp
src/details/VertexBuffer.cpp
src/details/View.cpp
+4 -11
View File
@@ -295,7 +295,6 @@ if (FILAMENT_SUPPORTS_WEBGPU)
src/webgpu/WebGPUStrings.h
src/webgpu/WebGPUSwapChain.cpp
src/webgpu/WebGPUSwapChain.h
src/webgpu/WebGPUSync.h
src/webgpu/WebGPUTexture.cpp
src/webgpu/WebGPUTexture.h
src/webgpu/WebGPUTextureHelpers.h
@@ -495,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)
@@ -578,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
@@ -629,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}")
@@ -664,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()
# ==================================================================================================
@@ -101,16 +101,6 @@ static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = SWAP_CHAIN_CON
*/
static constexpr uint64_t SWAP_CHAIN_CONFIG_PROTECTED_CONTENT = 0x40;
/**
* Indicates that the SwapChain is configured to use Multi-Sample Anti-Aliasing (MSAA) with the
* given sample points within each pixel. Only supported when isMSAASwapChainSupported(4) is
* true.
*
* This is only supported by EGL(Android). Other GL platforms (GLX, WGL, etc) don't support it
* because the swapchain MSAA settings must be configured before window creation.
*/
static constexpr uint64_t SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES = 0x80;
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
@@ -639,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
*/
@@ -38,7 +38,6 @@ struct HwRenderPrimitive;
struct HwRenderTarget;
struct HwStream;
struct HwSwapChain;
struct HwSync;
struct HwTexture;
struct HwTimerQuery;
struct HwVertexBufferInfo;
@@ -152,7 +151,6 @@ using RenderPrimitiveHandle = Handle<HwRenderPrimitive>;
using RenderTargetHandle = Handle<HwRenderTarget>;
using StreamHandle = Handle<HwStream>;
using SwapChainHandle = Handle<HwSwapChain>;
using SyncHandle = Handle<HwSync>;
using TextureHandle = Handle<HwTexture>;
using TimerQueryHandle = Handle<HwTimerQuery>;
using VertexBufferHandle = Handle<HwVertexBuffer>;
@@ -29,7 +29,6 @@
namespace filament::backend {
class CallbackHandler;
class Driver;
/**
@@ -43,9 +42,6 @@ public:
struct SwapChain {};
struct Fence {};
struct Stream {};
struct Sync {};
using SyncCallback = void(*)(Sync* UTILS_NONNULL sync, void* UTILS_NULLABLE userData);
class ExternalImageHandle;
@@ -27,12 +27,12 @@ namespace filament::backend {
* A PresentCallable is a callable object that, when called, schedules a frame for presentation on
* a SwapChain.
*
* Typically, Filament's backend is responsible for scheduling a frame's presentation. However,
* there are certain cases where the application might want to control when a frame is scheduled for
* Typically, Filament's backend is responsible scheduling a frame's presentation. However, there
* are certain cases where the application might want to control when a frame is scheduled for
* presentation.
*
* For example, on iOS, UIKit elements can be synchronized to 3D content by scheduling a present
* within a CATransaction:
* within a CATransation:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* void myFrameScheduledCallback(PresentCallable presentCallable, void* user) {
@@ -55,13 +55,12 @@ namespace filament::backend {
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @remark The PresentCallable mechanism for user-controlled presentation is only supported by
* Filament's Metal backend. On other backends, the FrameScheduledCallback is still invoked, but the
* PresentCallable passed to it is a no-op and calling it has no effect.
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
* backends ignore the callback (which will never be called) and proceed normally.
*
* When using the Metal backend, applications *must* call each PresentCallable they receive. Each
* PresentCallable represents a frame that is waiting to be presented, and failing to call it
* will result in a memory leak. To "cancel" the presentation of a frame, pass false to the
* Applications *must* call each PresentCallable they receive. Each PresentCallable represents a
* frame that is waiting to be presented. If an application fails to call a PresentCallable, a
* memory leak could occur. To "cancel" the presentation of a frame, pass false to the
* PresentCallable, which will cancel the presentation of the frame and release associated memory.
*
* @see Renderer, SwapChain::setFrameScheduledCallback
@@ -70,7 +69,6 @@ class UTILS_PUBLIC PresentCallable {
public:
using PresentFn = void(*)(bool presentFrame, void* user);
static void noopPresent(bool, void*) {}
PresentCallable(PresentFn fn, void* user) noexcept;
~PresentCallable() noexcept = default;
+4 -1
View File
@@ -20,6 +20,7 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/bitset.h>
#include <backend/DriverEnums.h>
@@ -66,6 +67,7 @@ public:
using DescriptorBindingsInfo = utils::FixedCapacityVector<Descriptor>;
using DescriptorSetInfo = std::array<DescriptorBindingsInfo, MAX_DESCRIPTOR_SET_COUNT>;
using SpecializationConstantsInfo = utils::FixedCapacityVector<SpecializationConstant>;
using MutableSpecConstantsInfo = utils::bitset8;
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
@@ -103,7 +105,8 @@ public:
Program& descriptorBindings(backend::descriptor_set_t set,
DescriptorBindingsInfo descriptorBindings) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept;
struct PushConstant {
utils::CString name;
@@ -85,15 +85,6 @@ public:
*/
virtual bool isSRGBSwapChainSupported() const noexcept;
/**
* Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_MSAA_*_SAMPLES flag.
* The default implementation returns false.
*
* @param samples The number of samples
* @return true if SWAP_CHAIN_CONFIG_MSAA_*_SAMPLES is supported, false otherwise.
*/
virtual bool isMSAASwapChainSupported(uint32_t samples) const noexcept;
/**
* Return whether protected contexts are supported by this backend.
* If protected context are supported, the SWAP_CHAIN_CONFIG_PROTECTED_CONTENT flag can be
@@ -285,26 +276,6 @@ public:
*/
virtual backend::FenceStatus waitFence(Fence* UTILS_NONNULL fence, uint64_t timeout) noexcept;
// --------------------------------------------------------------------------------------------
// Sync support
/**
* Creates a Sync. These can be used for frame synchronization externally
* (certain platform implementations can be exported to handles that can
* be used in other processes).
*
* @return A Sync object.
*/
virtual Platform::Sync* UTILS_NONNULL createSync() noexcept;
/**
* Destroys a sync. If called with a sync not created by this platform
* object, this will lead to undefined behavior.
*
* @param sync The sync to destroy, that was created by this platform
* instance.
*/
virtual void destroySync(Platform::Sync* UTILS_NONNULL sync) noexcept;
// --------------------------------------------------------------------------------------------
// Streaming support
@@ -98,9 +98,8 @@ protected:
void terminate() noexcept override;
bool isProtectedContextSupported() const noexcept override;
bool isSRGBSwapChainSupported() const noexcept override;
bool isMSAASwapChainSupported(uint32_t samples) const noexcept override;
bool isSRGBSwapChainSupported() const noexcept override;
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
@@ -58,17 +58,6 @@ public:
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(ExternalImageHandle externalImage) noexcept;
/**
* Converts a sync to an external file descriptor, if possible. Accepts an
* opaque handle to a sync, as well as a pointer to where the fd should be
* stored.
* @param sync The sync to be converted to a file descriptor.
* @param fd A pointer to where the file descriptor should be stored.
* @return `true` on success, `false` on failure. The default implementation
* returns `false`.
*/
bool convertSyncToFd(Platform::Sync* sync, int* fd) noexcept;
protected:
// --------------------------------------------------------------------------------------------
// Platform Interface
@@ -85,10 +74,6 @@ protected:
// --------------------------------------------------------------------------------------------
// OpenGLPlatform Interface
struct SyncEGLAndroid : public Platform::Sync {
EGLSyncKHR sync;
};
void terminate() noexcept override;
void beginFrame(
@@ -104,10 +89,9 @@ protected:
*/
void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept override;
Stream* createStream(void* nativeStream) noexcept override;
void destroyStream(Stream* stream) noexcept override;
Platform::Sync* createSync() noexcept override;
void destroySync(Platform::Sync* sync) noexcept override;
void attach(Stream* stream, intptr_t tname) noexcept override;
void detach(Stream* stream) noexcept override;
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override;
@@ -17,9 +17,8 @@
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
#include <backend/CallbackHandler.h>
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
#include <backend/DriverEnums.h>
#include <bluevk/BlueVK.h>
@@ -30,9 +29,9 @@
#include <cstddef>
#include <functional>
#include <string>
#include <tuple>
#include <unordered_set>
#include <string>
#include <stddef.h>
#include <stdint.h>
@@ -46,10 +45,6 @@ using SwapChain = Platform::SwapChain;
*/
struct VulkanPlatformPrivate;
// Forward declare the fence status that will be maintained by the command
// buffer manager.
struct VulkanCmdFence;
/**
* A Platform interface that creates a Vulkan backend.
*/
@@ -234,25 +229,6 @@ public:
virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0,
VkExtent2D extent = {0, 0});
/**
* Creates a Platform::Sync object, which tracks a fence and its status,
* and allows conversion to an external sync.
* @param fence The underlying VkFence to use for synchronization.
* @param fenceStatus An object tracking the fence's state
* @return A Platform::Sync object tracking the provided fence.
*/
virtual Platform::Sync* createSync(VkFence fence,
std::shared_ptr<VulkanCmdFence> fenceStatus) noexcept;
/**
* Destroys a sync. If called with a sync not created by this platform
* object, this will lead to undefined behavior.
*
* @param sync The sync to destroy, which was created by this platform
* instance.
*/
virtual void destroySync(Platform::Sync* sync) noexcept;
/**
* Allows implementers to provide instance extensions that they'd like to include in the
* instance creation.
@@ -432,19 +408,12 @@ public:
}
protected:
struct VulkanSync : public Platform::Sync {
VkFence fence;
std::shared_ptr<VulkanCmdFence> fenceStatus;
};
virtual ExtensionSet getSwapchainInstanceExtensions() const;
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept;
virtual VkExternalFenceHandleTypeFlagBits getFenceExportFlags() const noexcept;
private:
// Platform dependent helper methods
static ExtensionSet getSwapchainInstanceExtensionsImpl();
@@ -44,17 +44,6 @@ public:
virtual ImageData createVkImageFromExternal(ExternalImageHandleRef image) const override;
/**
* Converts a sync to an external file descriptor, if possible. Accepts an
* opaque handle to a sync, as well as a pointer to where the fd should be
* stored.
* @param sync The sync to be converted to a file descriptor.
* @param fd A pointer to where the file descriptor should be stored.
* @return `true` on success, `false` on failure. The default implementation
* returns `false`.
*/
bool convertSyncToFd(Platform::Sync* sync, int* fd) const noexcept;
protected:
virtual ExtensionSet getSwapchainInstanceExtensions() const override;
@@ -62,8 +51,6 @@ protected:
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept override;
virtual VkExternalFenceHandleTypeFlagBits getFenceExportFlags() const noexcept override;
private:
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
AHardwareBuffer* aHardwareBuffer = nullptr;
@@ -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,25 +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::SyncHandle, createSync)
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,
@@ -330,7 +328,6 @@ DECL_DRIVER_API_N(destroySwapChain, backend::SwapChainHandle, sch)
DECL_DRIVER_API_N(destroyStream, backend::StreamHandle, sh)
DECL_DRIVER_API_N(destroyTimerQuery, backend::TimerQueryHandle, sh)
DECL_DRIVER_API_N(destroyFence, backend::FenceHandle, fh)
DECL_DRIVER_API_N(destroySync, backend::SyncHandle, sh)
DECL_DRIVER_API_N(destroyDescriptorSetLayout, backend::DescriptorSetLayoutHandle, dslh)
DECL_DRIVER_API_N(destroyDescriptorSet, backend::DescriptorSetHandle, dsh)
@@ -340,15 +337,13 @@ 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)
DECL_DRIVER_API_SYNCHRONOUS_N(void, updateStreams, backend::DriverApi*, driver)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::FenceStatus, getFenceStatus, backend::FenceHandle, fh)
DECL_DRIVER_API_SYNCHRONOUS_N(void, getPlatformSync, backend::SyncHandle, sh,
backend::CallbackHandler*, handler, backend::Platform::SyncCallback, cb, void*, userData)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isTextureFormatSupported, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isTextureSwizzleSupported)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isTextureFormatMipmappable, backend::TextureFormat, format)
@@ -358,7 +353,6 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameBufferFetchMultiSampleSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameTimeSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isAutoDepthResolveSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isSRGBSwapChainSupported)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isMSAASwapChainSupported, uint32_t, samples)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedContentSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isStereoSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported)
@@ -249,9 +249,8 @@ public:
}
void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
if (tag.empty()) {
return;
}
// TODO: for now, only pool handles check for use-after-free, so we only keep tags for
// those
uint32_t key = id;
if (UTILS_LIKELY(isPoolHandle(id))) {
// Truncate the age to get the debug tag
-24
View File
@@ -38,11 +38,6 @@
#include <stdlib.h>
#include <string.h>
#if defined(WIN32)
# include <windows.h> // for VirtualAlloc, VirtualProtect, VirtualFree
# include <utils/unwindows.h>
#endif
using namespace utils;
namespace filament::backend {
@@ -139,21 +134,6 @@ void* CircularBuffer::alloc(size_t size) {
mprotect(guard, BLOCK_SIZE, PROT_NONE);
}
return data;
#elif defined(WIN32)
size_t const BLOCK_SIZE = getBlockSize();
// On Windows, use VirtualAlloc instead of malloc to allocate virtual memory.
// This allows us to set page protection by VirtualProtect.
void* data = VirtualAlloc(nullptr, size * 2 + BLOCK_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
FILAMENT_CHECK_POSTCONDITION(data != nullptr)
<< "couldn't allocate " << (size * 2 / 1024)
<< " KiB of virtual address space for the command buffer";
// guard page at the end
void* guard = (void*)(uintptr_t(data) + size * 2);
DWORD oldProtect = 0;
BOOL ok = VirtualProtect(guard, BLOCK_SIZE, PAGE_NOACCESS, &oldProtect);
FILAMENT_CHECK_POSTCONDITION(ok) << "VirtualProtect failed to set guard page";
return data;
#else
return ::malloc(2 * size);
#endif
@@ -170,10 +150,6 @@ void CircularBuffer::dealloc() noexcept {
mAshmemFd = -1;
}
}
#elif defined(WIN32)
if (mData) {
VirtualFree(mData, 0, MEM_RELEASE);
}
#else
::free(mData);
#endif
+5 -5
View File
@@ -57,7 +57,7 @@ static void printParameterPack(io::ostream& out, const FIRST& first, const REMAI
printParameterPack(out, rest...);
}
static UTILS_NOINLINE UTILS_UNUSED std::string_view extractMethodName(std::string_view command) noexcept {
static UTILS_NOINLINE UTILS_UNUSED std::string extractMethodName(std::string& command) noexcept {
constexpr const char startPattern[] = "::Command<&filament::backend::Driver::";
auto pos = command.rfind(startPattern);
auto end = command.rfind('(');
@@ -133,9 +133,9 @@ template<std::size_t... I>
void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log(std::index_sequence<I...>) noexcept {
#if DEBUG_COMMAND_STREAM
static_assert(UTILS_HAS_RTTI, "DEBUG_COMMAND_STREAM can only be used with RTTI");
CString command = CallStack::demangleTypeName(typeid(Command).name());
DLOG(INFO) << extractMethodName({command.data(), command.size()}) << " : size=" << sizeof(Command);
io::sstream parameterPack;
std::string command = utils::CallStack::demangleTypeName(typeid(Command).name()).c_str();
DLOG(INFO) << extractMethodName(command) << " : size=" << sizeof(Command);
utils::io::sstream parameterPack;
printParameterPack(parameterPack, std::get<I>(mArgs)...);
DLOG(INFO) << "\t" << parameterPack.c_str();
#endif
@@ -164,7 +164,7 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log() noexcept {
// ------------------------------------------------------------------------------------------------
void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) {
*next = align(sizeof(CustomCommand));
*next = CustomCommand::align(sizeof(CustomCommand));
static_cast<CustomCommand*>(base)->mCommand();
static_cast<CustomCommand*>(base)->~CustomCommand();
}
-4
View File
@@ -140,10 +140,6 @@ struct HwFence : public HwBase {
Platform::Fence* fence = nullptr;
};
struct HwSync : public HwBase {
Platform::Sync* sync = nullptr;
};
struct HwSwapChain : public HwBase {
Platform::SwapChain* swapChain = nullptr;
};
+6 -7
View File
@@ -21,8 +21,7 @@
#include <utils/ostream.h>
#ifndef NDEBUG
# include <utils/CString.h>
# include <string_view>
# include <string>
#endif
#include <stddef.h>
@@ -37,11 +36,11 @@ static char const * const kOurNamespace = "filament::backend::";
// removes all occurrences of "what" from "str"
UTILS_NOINLINE
static CString& removeAll(CString& str, const std::string_view what) noexcept {
static std::string& removeAll(std::string& str, const std::string& what) noexcept {
if (!what.empty()) {
const CString empty;
const std::string empty;
size_t pos = 0;
while ((pos = std::string_view{ str.data(), str.size() }.find(what, pos)) != std::string_view::npos) {
while ((pos = str.find(what, pos)) != std::string::npos) {
str.replace(pos, what.length(), empty);
}
}
@@ -50,13 +49,13 @@ static CString& removeAll(CString& str, const std::string_view what) noexcept {
template <typename T>
UTILS_NOINLINE
static io::ostream& logHandle(io::ostream& out, CString& typeName, T id) noexcept {
static io::ostream& logHandle(io::ostream& out, std::string& typeName, T id) noexcept {
return out << removeAll(typeName, kOurNamespace) << " @ " << id;
}
template <typename T>
io::ostream& operator<<(io::ostream& out, const Handle<T>& h) noexcept {
CString s{ CallStack::typeName<Handle<T>>() };
std::string s(CallStack::typeName<Handle<T>>().c_str());
return logHandle(out, s, h.getId());
}
+13 -2
View File
@@ -82,8 +82,19 @@ Program& Program::attributes(AttributesInfo attributes) noexcept {
return *this;
}
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants) noexcept {
mSpecializationConstants = std::move(specConstants);
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept {
// String the two lists together.
mSpecializationConstants = SpecializationConstantsInfo(
specConstants.size() + mutableSpecConstants.size());
std::uninitialized_move(specConstants.begin(), specConstants.end(),
mSpecializationConstants.begin());
for (uint32_t i = 0; i < mutableSpecConstants.size(); i++) {
mSpecializationConstants[i + specConstants.size()] = SpecializationConstant {
.id = i + firstMutableId,
.value = mutableSpecConstants[i],
};
}
return *this;
}
+1 -1
View File
@@ -153,7 +153,7 @@ private:
Type mType = Type::NONE;
static PlatformMetal* platform;
static std::array<std::atomic<uint64_t>, TypeCount> aliveBuffers;
static std::array<uint64_t, TypeCount> aliveBuffers;
};
class MetalBuffer {
+1 -1
View File
@@ -24,7 +24,7 @@
namespace filament {
namespace backend {
std::array<std::atomic<uint64_t>, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
std::array<uint64_t, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
PlatformMetal* TrackedMetalBuffer::platform = nullptr;
PlatformMetal* ScopedAllocationTimer::platform = nullptr;
+50 -85
View File
@@ -418,40 +418,49 @@ void MetalDriver::finish(int) {
}
void MetalDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes, utils::CString tag) {
uint8_t attributeCount, AttributeArray attributes) {
construct_handle<MetalVertexBufferInfo>(vbih, *mContext,
bufferCount, attributeCount, attributes);
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
}
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::CString tag) {
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih) {
MetalVertexBufferInfo const* const vbi = handle_cast<const MetalVertexBufferInfo>(vbih);
construct_handle<MetalVertexBuffer>(vbh, *mContext, vertexCount, vbi->bufferCount, vbih);
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
// No actual GPU memory is allocated here, so no need to check for allocation success.
}
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, utils::CString tag) {
uint32_t indexCount, BufferUsage usage) {
auto elementSize = (uint8_t)getElementTypeSize(elementType);
auto* indexBuffer =
construct_handle<MetalIndexBuffer>(ibh, *mContext, usage, elementSize, indexCount);
auto& buffer = indexBuffer->buffer;
FILAMENT_CHECK_POSTCONDITION(buffer.wasAllocationSuccessful())
<< "Could not allocate Metal index buffer of size " << buffer.getSize()
<< ", tag=" << tag.c_str_safe();
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
// If the allocation was not successful, postpone the error message until the next tick, to give
// Filament a chance to call setDebugTag on the handle; this way we get a nicer error message.
if (UTILS_UNLIKELY(!buffer.wasAllocationSuccessful())) {
const size_t byteCount = buffer.getSize();
runAtNextTick([byteCount, this, ibh]() {
FILAMENT_CHECK_POSTCONDITION(false)
<< "Could not allocate Metal index buffer of size " << byteCount
<< ", tag=" << mHandleAllocator.getHandleTag(ibh.getId()).c_str_safe();
});
}
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
BufferObjectBinding bindingType, BufferUsage usage) {
auto* bufferObject =
construct_handle<MetalBufferObject>(boh, *mContext, bindingType, usage, byteCount);
FILAMENT_CHECK_POSTCONDITION(bufferObject->getBuffer()->wasAllocationSuccessful())
<< "Could not allocate Metal buffer of size " << byteCount
<< ", tag=" << tag.c_str_safe();
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
// If the allocation was not successful, postpone the error message until the next tick, to give
// Filament a chance to call setDebugTag on the handle; this way we get a nicer error message.
if (UTILS_UNLIKELY(!bufferObject->getBuffer()->wasAllocationSuccessful())) {
runAtNextTick([byteCount, this, boh]() {
FILAMENT_CHECK_POSTCONDITION(false)
<< "Could not allocate Metal buffer of size " << byteCount
<< ", tag=" << mHandleAllocator.getHandleTag(boh.getId()).c_str_safe();
});
}
}
// fixme: TextureUsage is a bitfield
@@ -486,7 +495,7 @@ inline const char* stringify(SamplerType samplerType) {
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString tag) {
uint32_t depth, TextureUsage usage) {
// Clamp sample count to what the device supports.
auto& sc = mContext->sampleCountLookup;
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
@@ -498,60 +507,55 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
"createTextureR(th = %d, target = %s, levels = %d, format = ?, samples = %d, width = "
"%d, height = %d, depth = %d, usage = %s)\n",
th.getId(), stringify(target), levels, samples, width, height, depth, stringify(usage));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
void MetalDriver::createTextureViewR(
Handle<HwTexture> th, Handle<HwTexture> srch, uint8_t baseLevel, uint8_t levelCount) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
mContext->textures.insert(
construct_handle<MetalTexture>(th, *mContext, src, baseLevel, levelCount));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, utils::CString tag) {
backend::TextureSwizzle a) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef image, utils::CString tag) {
Platform::ExternalImageHandleRef image) {
// FIXME: implement createTextureExternalImage2R
}
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, utils::CString tag) {
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane, utils::CString tag) {
void* image, uint32_t plane) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image, plane));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString tag) {
uint32_t depth, TextureUsage usage) {
id<MTLTexture> metalTexture = (id<MTLTexture>) CFBridgingRelease((void*) i);
FILAMENT_CHECK_PRECONDITION(metalTexture.width == width)
<< "Imported id<MTLTexture> width (" << metalTexture.width
@@ -568,36 +572,32 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
<< ") != Filament texture type (" << filamentMetalType << ")";
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext,
target, levels, format, samples, width, height, depth, usage, metalTexture));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString tag) {
PrimitiveType pt) {
construct_handle<MetalRenderPrimitive>(rph);
MetalDriver::setRenderPrimitiveBuffer(rph, pt, vbh, ibh);
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::CString tag) {
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
#if FILAMENT_METAL_DEBUG_LOG
auto handleId = rph.getId();
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
DLOG(INFO) << program;
#endif
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString tag) {
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
construct_handle<MetalRenderTarget>(rth, mContext);
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, uint8_t layerCount, MRT color,
TargetBufferInfo depth, TargetBufferInfo stencil, utils::CString tag) {
TargetBufferInfo depth, TargetBufferInfo stencil) {
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
<< "createRenderTarget must be called outside of a render pass.";
// Clamp sample count to what the device supports.
@@ -640,20 +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) {
// TODO: support MSAA swapchain
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);
@@ -664,24 +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::createSyncR(Handle<HwSync> sh, utils::CString tag) {
// TODO: Ensure sync is active, and then invoke and clear all pending
// callbacks.
mHandleAllocator.associateTagToHandle(sh.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
@@ -718,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) {
@@ -739,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 {
@@ -824,10 +807,6 @@ Handle<HwSwapChain> MetalDriver::createSwapChainHeadlessS() noexcept {
return alloc_handle<MetalSwapChain>();
}
Handle<HwSync> MetalDriver::createSyncS() noexcept {
return alloc_handle<MetalSync>();
}
Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
// The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen
// before createTimerQueryR is executed.
@@ -990,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 {};
}
@@ -1029,19 +1008,6 @@ FenceStatus MetalDriver::getFenceStatus(Handle<HwFence> fh) {
return fence->wait(0);
}
void MetalDriver::destroySync(Handle<HwSync> sh) {
if (sh) {
destruct_handle<MetalSync>(sh);
}
}
void MetalDriver::getPlatformSync(Handle<HwSync> sh, CallbackHandler* handler,
Platform::SyncCallback cb, void* userData) {
// TODO: If the sync has been inserted into the command stream, execute
// the callback. Otherwise, enqueue it.
}
bool MetalDriver::isTextureFormatSupported(TextureFormat format) {
return MetalTexture::decidePixelFormat(mContext, format) != MTLPixelFormatInvalid;
}
@@ -1123,11 +1089,6 @@ bool MetalDriver::isSRGBSwapChainSupported() {
return false;
}
bool MetalDriver::isMSAASwapChainSupported(uint32_t) {
// TODO: support MSAA swapchain
return false;
}
bool MetalDriver::isProtectedContentSupported() {
// the SWAP_CHAIN_CONFIG_PROTECTED_CONTENT flag is not supported
return false;
@@ -2174,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);
}
@@ -437,10 +437,6 @@ private:
uint64_t value;
};
// TODO: Provide implementation for MetalSync.
class MetalSync : public HwSync {
};
struct MetalTimerQuery : public HwTimerQuery {
MetalTimerQuery() : status(std::make_shared<Status>()) {}
+7 -14
View File
@@ -16,11 +16,12 @@
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/Platform.h>
#include "noop/NoopDriver.h"
#include "CommandStreamDispatcher.h"
#include <backend/Handle.h>
#include <stdint.h>
namespace filament::backend {
@@ -115,9 +116,6 @@ void NoopDriver::destroySwapChain(Handle<HwSwapChain> sch) {
void NoopDriver::destroyStream(Handle<HwStream> sh) {
}
void NoopDriver::destroySync(Handle<HwSync> sh) {
}
void NoopDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
}
@@ -127,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 {};
}
@@ -149,10 +147,6 @@ int64_t NoopDriver::getStreamTimestamp(Handle<HwStream> sh) {
void NoopDriver::updateStreams(CommandStream* driver) {
}
void NoopDriver::getPlatformSync(Handle<HwSync> sh, CallbackHandler* handler,
Platform::SyncCallback cb, void* userData) {
}
void NoopDriver::destroyFence(Handle<HwFence> fh) {
}
@@ -198,10 +192,6 @@ bool NoopDriver::isSRGBSwapChainSupported() {
return false;
}
bool NoopDriver::isMSAASwapChainSupported(uint32_t) {
return false;
}
bool NoopDriver::isProtectedContentSupported() {
return false;
}
@@ -425,4 +415,7 @@ void NoopDriver::bindDescriptorSet(
backend::DescriptorSetOffsetArray&& offsets) {
}
void NoopDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
}
} // namespace filament
+34 -148
View File
@@ -149,18 +149,6 @@ using namespace utils;
namespace filament::backend {
namespace {
static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
std::unique_ptr<OpenGLDriver::GLSyncFence::CallbackData> cbData(
static_cast<OpenGLDriver::GLSyncFence::CallbackData*>(userData));
// This assumes the sync has not yet been destroyed. If it has, this will be
// undefined behavior.
cbData->cb(cbData->sync, cbData->userData);
};
} // namespace
Driver* OpenGLDriverFactory::create(
OpenGLPlatform* platform,
void* sharedGLContext,
@@ -627,10 +615,6 @@ Handle<HwFence> OpenGLDriver::createFenceS() noexcept {
return initHandle<GLFence>();
}
Handle<HwSync> OpenGLDriver::createSyncS() noexcept {
return initHandle<GLSyncFence>();
}
Handle<HwSwapChain> OpenGLDriver::createSwapChainS() noexcept {
return initHandle<GLSwapChain>();
}
@@ -655,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;
@@ -689,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);
@@ -715,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;
@@ -753,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()
@@ -784,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
@@ -889,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);
@@ -978,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);
@@ -1025,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);
@@ -1090,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;
@@ -1142,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;
@@ -1193,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;
@@ -1257,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) {
@@ -1659,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
@@ -1670,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,
@@ -1681,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);
@@ -1795,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);
@@ -1820,29 +1784,9 @@ void OpenGLDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
});
}
#endif
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
}
void OpenGLDriver::createSyncR(Handle<HwSync> sh, utils::CString tag) {
DEBUG_MARKER()
GLSyncFence* s = handle_cast<GLSyncFence*>(sh);
{
std::lock_guard<std::mutex> guard(s->lock);
s->sync = mPlatform.createSync();
}
for (auto& cbData : s->conversionCallbacks) {
cbData->sync = s->sync;
scheduleCallback(cbData->handler, cbData.release(), syncCallbackWrapper);
}
s->conversionCallbacks.clear();
mHandleAllocator.associateTagToHandle(sh.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);
@@ -1859,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);
@@ -1882,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));
}
// ------------------------------------------------------------------------------------------------
@@ -2011,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);
@@ -2114,16 +2051,6 @@ void OpenGLDriver::destroyStream(Handle<HwStream> sh) {
}
}
void OpenGLDriver::destroySync(Handle<HwSync> sh) {
DEBUG_MARKER()
if (sh) {
GLSyncFence* s = handle_cast<GLSyncFence*>(sh);
mPlatform.destroySync(s->sync);
destruct(sh, s);
}
}
void OpenGLDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
DEBUG_MARKER()
@@ -2161,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
@@ -2312,33 +2235,6 @@ FenceStatus OpenGLDriver::getFenceStatus(Handle<HwFence> fh) {
return FenceStatus::ERROR;
}
void OpenGLDriver::getPlatformSync(Handle<HwSync> sh, CallbackHandler* handler,
Platform::SyncCallback cb, void* userData) {
if (!sh) {
return;
}
GLSyncFence* s = handle_cast<GLSyncFence*>(sh);
auto cbData = std::make_unique<GLSyncFence::CallbackData>();
cbData->handler = handler;
cbData->cb = cb;
cbData->userData = userData;
// If we haven't already set the handle, toss the conversion callback in the
// back of the list.
{
std::lock_guard guard(s->lock);
if (s->sync == nullptr) {
s->conversionCallbacks.push_back(std::move(cbData));
return;
}
}
// Otherwise, go ahead and schedule the callback now.
cbData->sync = s->sync;
scheduleCallback(cbData->handler, cbData.release(), syncCallbackWrapper);
}
bool OpenGLDriver::isTextureFormatSupported(TextureFormat format) {
const auto& ext = mContext.ext;
if (isETC2Compression(format)) {
@@ -2504,10 +2400,6 @@ bool OpenGLDriver::isSRGBSwapChainSupported() {
return mPlatform.isSRGBSwapChainSupported();
}
bool OpenGLDriver::isMSAASwapChainSupported(uint32_t samples) {
return mPlatform.isMSAASwapChainSupported(samples);
}
bool OpenGLDriver::isProtectedContentSupported() {
return mPlatform.isProtectedContextSupported();
}
@@ -2622,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)]() {
@@ -2701,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()
@@ -3828,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 {
@@ -198,19 +193,6 @@ public:
std::shared_ptr<State> state{ std::make_shared<State>() };
};
// Note: named "GLSyncFence" to avoid confusion with the GL handle,
// "GLsync" (lowercase S)
struct GLSyncFence : public HwSync {
struct CallbackData {
CallbackHandler* handler;
Platform::SyncCallback cb;
Platform::Sync* sync;
void* userData;
};
std::mutex lock;
std::vector<std::unique_ptr<CallbackData>> conversionCallbacks;
};
OpenGLDriver(OpenGLDriver const&) = delete;
OpenGLDriver& operator=(OpenGLDriver const&) = delete;
@@ -76,10 +76,6 @@ bool OpenGLPlatform::isSRGBSwapChainSupported() const noexcept {
return false;
}
bool OpenGLPlatform::isMSAASwapChainSupported(uint32_t) const noexcept {
return false;
}
uint32_t OpenGLPlatform::getDefaultFramebufferObject() noexcept {
return 0;
}
@@ -121,15 +117,6 @@ FenceStatus OpenGLPlatform::waitFence(
return FenceStatus::ERROR;
}
Platform::Sync* OpenGLPlatform::createSync() noexcept {
return new Platform::Sync();
}
void OpenGLPlatform::destroySync(Platform::Sync* sync) noexcept {
// sync must be a Platform::Sync, since it was created by this platform
// object.
delete sync;
}
Platform::Stream* OpenGLPlatform::createStream(
UTILS_UNUSED void* nativeStream) noexcept {
@@ -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;
@@ -448,11 +448,6 @@ EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags, bool window, bool pbu
configAttribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
}
if (flags & SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES) {
configAttribs[EGL_SAMPLE_BUFFERS] = 1;
configAttribs[EGL_SAMPLES] = 4;
}
if (UTILS_UNLIKELY(
!eglChooseConfig(mEGLDisplay, configAttribs.data(), &config, 1, &configsCount))) {
logEglError("eglChooseConfig");
@@ -486,48 +481,11 @@ bool PlatformEGL::isSRGBSwapChainSupported() const noexcept {
return ext.egl.KHR_gl_colorspace;
}
bool PlatformEGL::isMSAASwapChainSupported(uint32_t samples) const noexcept {
if (samples <= 1) {
return true;
}
Config configAttribs = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT },
{ EGL_RED_SIZE, 8 },
{ EGL_GREEN_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
{ EGL_DEPTH_SIZE, 24 },
{ EGL_SAMPLE_BUFFERS, 1 },
{ EGL_SAMPLES, samples },
};
if (!ext.egl.KHR_no_config_context) {
if (isOpenGL()) {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT;
} else {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT;
if (ext.egl.KHR_create_context) {
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
}
}
}
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint configsCount;
if (!eglChooseConfig(mEGLDisplay, configAttribs.data(), &config, 1, &configsCount)) {
return false;
}
return configsCount > 0;
}
Platform::SwapChain* PlatformEGL::createSwapChain(
void* nativeWindow, uint64_t flags) noexcept {
Config attribs;
// Remove flags for unsupported features.
if (isSRGBSwapChainSupported()) {
if (ext.egl.KHR_gl_colorspace) {
if (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) {
attribs[EGL_GL_COLORSPACE_KHR] = EGL_GL_COLORSPACE_SRGB_KHR;
}
@@ -535,7 +493,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
flags &= ~SWAP_CHAIN_CONFIG_SRGB_COLORSPACE;
}
if (isProtectedContextSupported()) {
if (ext.egl.EXT_protected_content) {
if (flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) {
attribs[EGL_PROTECTED_CONTENT_EXT] = EGL_TRUE;
}
@@ -543,13 +501,6 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
flags &= ~SWAP_CHAIN_CONFIG_PROTECTED_CONTENT;
}
if (flags & SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES) {
if (!isMSAASwapChainSupported(4)) {
flags &= ~SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES;
}
}
// Retrieve a config for the given flags.
EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags, true, false);
@@ -83,7 +83,6 @@ UTILS_PRIVATE PFNEGLGETCOMPOSITORTIMINGANDROIDPROC eglGetCompositorTimingANDROID
UTILS_PRIVATE PFNEGLGETNEXTFRAMEIDANDROIDPROC eglGetNextFrameIdANDROID = {};
UTILS_PRIVATE PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC eglGetFrameTimestampSupportedANDROID = {};
UTILS_PRIVATE PFNEGLGETFRAMETIMESTAMPSANDROIDPROC eglGetFrameTimestampsANDROID = {};
UTILS_PRIVATE PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = {};
}
using namespace glext;
@@ -227,8 +226,6 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
"eglGetFrameTimestampSupportedANDROID");
eglGetFrameTimestampsANDROID = (PFNEGLGETFRAMETIMESTAMPSANDROIDPROC)eglGetProcAddress(
"eglGetFrameTimestampsANDROID");
eglDupNativeFenceFDANDROID =
(PFNEGLDUPNATIVEFENCEFDANDROIDPROC) eglGetProcAddress("eglDupNativeFenceFDANDROID");
}
mAssertNativeWindowIsValid = driverConfig.assertNativeWindowIsValid;
@@ -398,31 +395,6 @@ void PlatformEGLAndroid::destroyStream(Platform::Stream* stream) noexcept {
mExternalStreamManager.release(stream);
}
Platform::Sync* PlatformEGLAndroid::createSync() noexcept {
auto sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
return new SyncEGLAndroid{.sync = sync};
}
bool PlatformEGLAndroid::convertSyncToFd(Platform::Sync* sync, int* fd) noexcept {
assert_invariant(sync && fd);
SyncEGLAndroid& eglSync = static_cast<SyncEGLAndroid&>(*sync);
*fd = eglDupNativeFenceFDANDROID(mEGLDisplay, eglSync.sync);
// In the case where there was no native FD, -1 is returned. Return false
// to indicate there was an error in this case.
if (*fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
LOG(ERROR) << "Failed to convert sync to fd: " << eglGetError();
return false;
}
return true;
}
void PlatformEGLAndroid::destroySync(Platform::Sync* sync) noexcept {
assert_invariant(sync);
SyncEGLAndroid& eglSync = static_cast<SyncEGLAndroid&>(*sync);
eglDestroySyncKHR(mEGLDisplay, eglSync.sync);
delete sync;
}
void PlatformEGLAndroid::attach(Stream* stream, intptr_t tname) noexcept {
mExternalStreamManager.attach(stream, tname);
}
@@ -20,7 +20,6 @@
#include <bluevk/BlueVK.h>
#include "DriverBase.h"
#include "backend/Platform.h"
#include "vulkan/memory/Resource.h"
@@ -53,19 +52,6 @@ struct VulkanFence : public HwFence, fvkmemory::ThreadSafeResource {
std::shared_ptr<VulkanCmdFence> fence;
};
struct VulkanSync : fvkmemory::ThreadSafeResource, public HwSync {
struct CallbackData {
CallbackHandler* handler;
Platform::SyncCallback cb;
Platform::Sync* sync;
void* userData;
};
VulkanSync() {}
std::mutex lock;
std::vector<std::unique_ptr<CallbackData>> conversionCallbacks;
};
struct VulkanTimerQuery : public HwTimerQuery, fvkmemory::ThreadSafeResource {
VulkanTimerQuery(uint32_t startingIndex, uint32_t stoppingIndex)
: mStartingQueryIndex(startingIndex),
@@ -96,6 +96,7 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect
VulkanLayout oldSrcLayout = src.getLayout();
VulkanLayout oldDstLayout = dst.getLayout();
src.texture->transitionLayout(commands, srcRange, VulkanLayout::TRANSFER_SRC);
dst.texture->transitionLayout(commands, dstRange, VulkanLayout::TRANSFER_DST);
assert_invariant(
@@ -108,9 +109,10 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect
.extent = { src.getExtent2D().width, src.getExtent2D().height, 1 },
}};
vkCmdResolveImage(cmdbuffer,
src.getImage(), fvkutils::getVkLayout(src.getLayout()),
src.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC),
dst.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST),
1, resolveRegions);
if (oldSrcLayout == VulkanLayout::UNDEFINED) {
oldSrcLayout = src.texture->getDefaultLayout();
}
+12 -31
View File
@@ -24,7 +24,6 @@
#include "VulkanConstants.h"
#include "VulkanContext.h"
#include <utils/CString.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/debug.h>
@@ -58,26 +57,26 @@ VkCommandBuffer createCommandBuffer(VkDevice device, VkCommandPool pool) {
} // anonymous namespace
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
void VulkanGroupMarkers::push(CString const& marker, Timestamp start) noexcept {
void VulkanGroupMarkers::push(std::string const& marker, Timestamp start) noexcept {
mMarkers.push_back({marker,
start.time_since_epoch().count() > 0.0
? start
: std::chrono::high_resolution_clock::now()});
}
std::pair<CString, Timestamp> VulkanGroupMarkers::pop() noexcept {
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop() noexcept {
auto ret = mMarkers.back();
mMarkers.pop_back();
return ret;
}
std::pair<CString, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
auto ret = mMarkers.front();
mMarkers.pop_front();
return ret;
}
std::pair<CString, Timestamp> const& VulkanGroupMarkers::top() const {
std::pair<std::string, Timestamp> const& VulkanGroupMarkers::top() const {
assert_invariant(!empty());
return mMarkers.back();
}
@@ -103,12 +102,6 @@ VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext const& context, VkDevice
vkCreateSemaphore(mDevice, &sci, VKALLOC, &mSubmission);
VkFenceCreateInfo fenceCreateInfo{.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
VkExportFenceCreateInfo exportFenceCreateInfo{
.sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
.handleTypes = context.getFenceExportFlags()
};
fenceCreateInfo.pNext = &exportFenceCreateInfo;
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &mFence);
}
@@ -218,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
@@ -360,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 "";
}
@@ -371,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();
@@ -431,9 +422,6 @@ bool VulkanCommands::flush() {
VkSemaphore lastSubmit = mLastSubmit;
bool hasFlushed = false;
VkFence flushedFence = VK_NULL_HANDLE;
std::shared_ptr<VulkanCmdFence> flushedFenceStatus;
// Note that we've ordered it so that the non-protected commands are followed by the protected
// commands. This assumes that the protected commands will be that one doing the rendering into
// the protected memory (i.e. protected render target).
@@ -446,17 +434,12 @@ 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;
}
flushedFence = pool->getRecording().getVkFence();
flushedFenceStatus = pool->getRecording().getFenceStatus();
dependency = pool->flush();
hasFlushed = true;
}
@@ -464,8 +447,6 @@ bool VulkanCommands::flush() {
if (hasFlushed) {
mInjectedDependency = VK_NULL_HANDLE;
mLastSubmit = dependency;
mLastFence = flushedFence;
mLastFenceStatus = flushedFenceStatus;
}
return true;
@@ -542,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();
}
+10 -21
View File
@@ -28,7 +28,6 @@
#include "vulkan/utils/StaticVector.h"
#include <utils/Condition.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Mutex.h>
@@ -36,6 +35,7 @@
#include <chrono>
#include <list>
#include <string>
#include <utility>
namespace filament::backend {
@@ -47,14 +47,14 @@ class VulkanGroupMarkers {
public:
using Timestamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
void push(utils::CString const& marker, Timestamp start = {}) noexcept;
std::pair<utils::CString, Timestamp> pop() noexcept;
std::pair<utils::CString, Timestamp> pop_bottom() noexcept;
std::pair<utils::CString, Timestamp> const& top() const;
void push(std::string const& marker, Timestamp start = {}) noexcept;
std::pair<std::string, Timestamp> pop() noexcept;
std::pair<std::string, Timestamp> pop_bottom() noexcept;
std::pair<std::string, Timestamp> const& top() const;
bool empty() const noexcept;
private:
std::list<std::pair<utils::CString, Timestamp>> mMarkers;
std::list<std::pair<std::string, Timestamp>> mMarkers;
};
#endif // FVK_DEBUG_GROUP_MARKERS
@@ -148,9 +148,9 @@ struct CommandBufferPool {
void waitFor(VkSemaphore previousAction, VkPipelineStageFlags waitStage);
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
utils::CString topMarker() const;
std::string topMarker() const;
void pushMarker(char const* marker, VulkanGroupMarkers::Timestamp timestamp);
std::pair<utils::CString, VulkanGroupMarkers::Timestamp> popMarker();
std::pair<std::string, VulkanGroupMarkers::Timestamp> popMarker();
void insertEvent(char const* marker);
#endif
@@ -223,19 +223,11 @@ public:
// it from the existing dependency chain. This is especially useful for setting up
// vkQueuePresentKHR.
VkSemaphore acquireFinishedSignal() {
VkSemaphore ret = mLastSubmit;
VkSemaphore ret= mLastSubmit;
mLastSubmit = VK_NULL_HANDLE;
return ret;
}
VkFence getMostRecentFence() {
return mLastFence;
}
std::shared_ptr<VulkanCmdFence> getMostRecentFenceStatus() {
return mLastFenceStatus;
}
// Takes a semaphore that signals when the next flush can occur. Only one injected
// semaphore is allowed per flush. Useful after calling vkAcquireNextImageKHR.
// waitStage
@@ -257,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:
@@ -273,9 +265,6 @@ private:
VkSemaphore mInjectedDependency = VK_NULL_HANDLE;
VkSemaphore mLastSubmit = VK_NULL_HANDLE;
VkFence mLastFence = VK_NULL_HANDLE;
std::shared_ptr<VulkanCmdFence> mLastFenceStatus;
VkPipelineStageFlags mInjectedDependencyWaitStage = 0;
};
@@ -106,10 +106,6 @@ public:
return mPhysicalDeviceProperties.properties.vendorID;
}
inline VkExternalFenceHandleTypeFlags getFenceExportFlags() const noexcept {
return mFenceExportFlags;
}
inline bool isImageCubeArraySupported() const noexcept {
return mPhysicalDeviceFeatures.features.imageCubeArray == VK_TRUE;
}
@@ -172,9 +168,6 @@ private:
// non-conformant vulkan implementation).
.imageView2DOn3DImage = VK_TRUE,
};
VkExternalFenceHandleTypeFlags mFenceExportFlags = {};
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;
bool mLazilyAllocatedMemorySupported = false;
+42 -166
View File
@@ -35,7 +35,6 @@
#include <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatform.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/Panic.h>
@@ -137,13 +136,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
}
#endif // FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
std::unique_ptr<VulkanSync::CallbackData> cbData(
static_cast<VulkanSync::CallbackData*>(userData));
// This assumes the sync has not yet been destroyed. If it has, this will be
// undefined behavior.
cbData->cb(cbData->sync, cbData->userData);
};
}// anonymous namespace
@@ -240,7 +232,6 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
mExternalImageManager(platform, &mSamplerCache, &mYcbcrConversionCache, &mDescriptorSetCache,
&mDescriptorSetLayoutCache),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
mIsMSAASwapChainSupported(false), // TODO: support MSAA swapchain
mStereoscopicType(driverConfig.stereoscopicType) {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
@@ -425,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,
@@ -485,16 +474,6 @@ void VulkanDriver::finish(int dummy) {
FVK_SYSTRACE_SCOPE();
endCommandRecording();
// It's not enough to wait on the fences of the buffers submitted. Present calls are
// submitted to this same queue, so the more correct option is to call vkQueueWaitIdle.
vkQueueWaitIdle(mPlatform->getGraphicsQueue());
if (auto protectedQueue = mPlatform->getProtectedGraphicsQueue();
UTILS_UNLIKELY(protectedQueue != VK_NULL_HANDLE)) {
vkQueueWaitIdle(protectedQueue);
}
// This wait() is still necessary to update the fence status.
mCommands.wait();
mReadPixels.runUntilComplete();
@@ -502,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) {
@@ -521,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) {
@@ -539,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) {
@@ -558,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) {
@@ -577,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) {
@@ -596,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,
@@ -609,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);
@@ -682,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
@@ -695,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) {
@@ -718,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) {
@@ -734,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();
@@ -808,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) {
@@ -818,13 +782,15 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
}
auto rt = resource_ptr<VulkanRenderTarget>::cast(&mResourceManager, rth);
// Note that the default render target will be destroyed on shutdown
if (UTILS_LIKELY(rt != mDefaultRenderTarget)) {
if (UTILS_UNLIKELY(rt == mDefaultRenderTarget)) {
// Note that this should only happen on driver shutdown.
mDefaultRenderTarget = {};
} else {
rt.dec();
}
}
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
VulkanCommandBuffer* cmdbuf;
if (mCurrentRenderPass.commandBuffer) {
cmdbuf = mCurrentRenderPass.commandBuffer;
@@ -836,57 +802,19 @@ 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::createSyncR(Handle<HwSync> sh, utils::CString tag) {
auto sync = resource_ptr<VulkanSync>::cast(&mResourceManager, sh);
VkFence fence = VK_NULL_HANDLE;
std::shared_ptr<VulkanCmdFence> fenceStatus;
if (mCurrentRenderPass.commandBuffer) {
VulkanCommandBuffer* cmdBuff = mCurrentRenderPass.commandBuffer;
fence = cmdBuff->getVkFence();
fenceStatus = cmdBuff->getFenceStatus();
// If we're currently recording, flush so that the fence only applies
// to commands already issued.
mCommands.flush();
} else {
fence = mCommands.getMostRecentFence();
fenceStatus = mCommands.getMostRecentFenceStatus();
}
{
std::lock_guard<std::mutex> guard(sync->lock);
sync->sync = mPlatform->createSync(fence, fenceStatus);
}
for (auto& cbData : sync->conversionCallbacks) {
cbData->sync = sync->sync;
scheduleCallback(cbData->handler, cbData.release(), syncCallbackWrapper);
}
sync->conversionCallbacks.clear();
mResourceManager.associateHandle(sh.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
// vkCreateSwapchainKHR with VK_ERROR_NATIVE_WINDOW_IN_USE_KHR.
mResourceManager.gc();
// TODO: support MSAA swapchain
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);
}
if ((flags & backend::SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES) != 0 && !isMSAASwapChainSupported(4)) {
FVK_LOGW << "MSAAx4 swapchain requested, but Platform does not support it";
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_MSAA_4_SAMPLES);
}
if (flags & backend::SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) {
if (!isProtectedContentSupported()) {
FVK_LOGW << "protected swapchain requested, but Platform does not support it";
@@ -895,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);
@@ -909,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);
@@ -936,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 {
@@ -1007,13 +929,6 @@ Handle<HwFence> VulkanDriver::createFenceS() noexcept {
return handle;
}
Handle<HwSync> VulkanDriver::createSyncS() noexcept {
auto handle = mResourceManager.allocHandle<VulkanSync>();
auto sync = resource_ptr<VulkanSync>::make(&mResourceManager, handle);
sync.inc();
return handle;
}
Handle<HwSwapChain> VulkanDriver::createSwapChainS() noexcept {
return mResourceManager.allocHandle<VulkanSwapChain>();
}
@@ -1052,17 +967,6 @@ void VulkanDriver::destroySwapChain(Handle<HwSwapChain> sch) {
void VulkanDriver::destroyStream(Handle<HwStream> sh) {
}
void VulkanDriver::destroySync(Handle<HwSync> sh) {
if (!sh) {
return;
}
FVK_SYSTRACE_SCOPE();
auto sync = resource_ptr<VulkanSync>::cast(&mResourceManager, sh);
mPlatform->destroySync(sync->sync);
sync.dec();
}
void VulkanDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
if (!tqh) {
return;
@@ -1081,16 +985,16 @@ void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
set.dec();
if (mAppState.hasExternalSamplers()) {
if (mAppState.hasExternalSamplers() && set->getExternalSamplerVkSet() != VK_NULL_HANDLE) {
mExternalImageManager.removeDescriptorSet(set);
}
}
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 {};
}
@@ -1138,29 +1042,6 @@ FenceStatus VulkanDriver::getFenceStatus(Handle<HwFence> fh) {
return FenceStatus::TIMEOUT_EXPIRED;
}
void VulkanDriver::getPlatformSync(Handle<HwSync> sh, CallbackHandler* handler,
Platform::SyncCallback cb, void* userData) {
auto sync = resource_ptr<VulkanSync>::cast(&mResourceManager, sh);
auto cbData = std::make_unique<VulkanSync::CallbackData>();
cbData->handler = handler;
cbData->cb = cb;
cbData->userData = userData;
// If we haven't already set the handle, toss the conversion callback in the
// back of the list.
{
std::lock_guard guard(sync->lock);
if (sync->sync == nullptr) {
sync->conversionCallbacks.push_back(std::move(cbData));
return;
}
}
// Otherwise, go ahead and schedule the callback now.
cbData->sync = sync->sync;
scheduleCallback(cbData->handler, cbData.release(), syncCallbackWrapper);
}
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
// the GPU supports the given texture format with non-zero optimal tiling features.
bool VulkanDriver::isTextureFormatSupported(TextureFormat format) {
@@ -1223,10 +1104,6 @@ bool VulkanDriver::isSRGBSwapChainSupported() {
return mIsSRGBSwapChainSupported;
}
bool VulkanDriver::isMSAASwapChainSupported(uint32_t) {
return mIsMSAASwapChainSupported;
}
bool VulkanDriver::isProtectedContentSupported() {
return mContext.isProtectedMemorySupported();
}
@@ -1730,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,
@@ -1911,14 +1788,9 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers,
VkOffset3D const srcOffsets[2] = { { srcLeft, srcTop, 0 }, { srcRight, srcBottom, 1 }};
VkOffset3D const dstOffsets[2] = { { dstLeft, dstTop, 0 }, { dstRight, dstBottom, 1 }};
auto const& dstAttachment = dstTarget->getColor0();
auto const& srcAttachment = srcTarget->getColor0();
if (srcAttachment.texture->samples > 1) {
mBlitter.resolve(dstAttachment, srcAttachment);
} else {
mBlitter.blit(vkfilter, dstAttachment, dstOffsets, srcAttachment, srcOffsets);
}
mBlitter.blit(vkfilter,
dstTarget->getColor0(), dstOffsets,
srcTarget->getColor0(), srcOffsets);
}
void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
@@ -2207,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();
@@ -187,7 +187,6 @@ private:
} mAppState;
bool const mIsSRGBSwapChainSupported;
bool const mIsMSAASwapChainSupported;
backend::StereoscopicType const mStereoscopicType;
};
@@ -32,7 +32,6 @@
#include <utils/compiler.h> // UTILS_FALLTHROUGH
#include <utils/Panic.h> // ASSERT_POSTCONDITION
#include <utils/CString.h>
using namespace bluevk;
@@ -286,7 +285,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
<< " error=" << static_cast<int32_t>(result);
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
utils::CString name{ builder.getName().c_str(), builder.getName().size() };
std::string name{ builder.getName().c_str(), builder.getName().size() };
switch (static_cast<ShaderStage>(i)) {
case ShaderStage::VERTEX:
name += "_vs";
+1 -6
View File
@@ -308,10 +308,7 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
// Creates a special "default" render target (i.e. associated with the swap chain)
explicit VulkanRenderTarget();
VulkanRenderTarget(VulkanRenderTarget&& target)
: HwRenderTarget(0, 0),
mOffscreen(false),
mProtected(false) {
VulkanRenderTarget(VulkanRenderTarget&& target) {
swap(std::move(target));
}
@@ -368,8 +365,6 @@ struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource {
private:
void swap(VulkanRenderTarget&& target) {
std::swap(width, target.width);
std::swap(height, target.height);
std::swap(mOffscreen, target.mOffscreen);
std::swap(mProtected, target.mProtected);
std::swap(mInfo, target.mInfo);
@@ -93,7 +93,7 @@ void VulkanSwapChain::update() {
mLayerCount = bundle.layerCount;
}
void VulkanSwapChain::present(DriverBase& driver) {
void VulkanSwapChain::present() {
if (!mHeadless && mTransitionSwapChainImageLayoutForPresent) {
VulkanCommandBuffer& commands = mCommands->get();
VkImageSubresourceRange const subresources{
@@ -120,14 +120,6 @@ void VulkanSwapChain::present(DriverBase& driver) {
// We presented the last acquired buffer.
mAcquired = false;
mIsFirstRenderPass = true;
if (frameScheduled.callback) {
driver.scheduleCallback(frameScheduled.handler,
[callback = std::move(frameScheduled.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback(noop);
});
}
}
void VulkanSwapChain::acquire(bool& resized) {
+1 -14
View File
@@ -47,7 +47,7 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
~VulkanSwapChain();
void present(DriverBase& driver);
void present();
// Acquire a new image from the swapchain. If the image is not available it would wait until it
// is.
@@ -79,13 +79,6 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
inline bool isProtected() noexcept {
return mPlatform->isProtected(swapChain);
}
inline void setFrameScheduledCallback(CallbackHandler* handler,
FrameScheduledCallback&& callback) noexcept {
frameScheduled.handler = handler;
frameScheduled.callback = std::move(callback);
}
private:
static constexpr int IMAGE_READY_SEMAPHORE_COUNT = FVK_MAX_COMMAND_BUFFERS;
@@ -101,12 +94,6 @@ private:
bool const mFlushAndWaitOnResize;
bool const mTransitionSwapChainImageLayoutForPresent;
// These fields store a callback to notify the client that Filament is commiting a frame.
struct {
CallbackHandler* handler = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
// transitions, which are useful here.
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
@@ -106,7 +106,7 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
return { vals[0], vals[1], vals[2], vals[3] };
};
// We make sure all identities are mapped into respective channels so that actual channel
// We make sure all all identities are mapped into respective channels so that actual channel
// mapping will be passed onto the output.
VkComponentMapping const prevExplicit = identityToChannel(prev);
VkComponentMapping const nextExplicit = identityToChannel(next);
@@ -38,7 +38,6 @@ template ResourceType getTypeEnum<VulkanDescriptorSetLayout>() noexcept;
template ResourceType getTypeEnum<VulkanDescriptorSet>() noexcept;
template ResourceType getTypeEnum<VulkanFence>() noexcept;
template ResourceType getTypeEnum<VulkanBuffer>() noexcept;
template ResourceType getTypeEnum<VulkanSync>() noexcept;
template<typename D>
ResourceType getTypeEnum() noexcept {
@@ -93,13 +92,10 @@ ResourceType getTypeEnum() noexcept {
if constexpr (std::is_same_v<D, VulkanBuffer>) {
return ResourceType::VULKAN_BUFFER;
}
if constexpr (std::is_same_v<D, VulkanSync>) {
return ResourceType::SYNC;
}
return ResourceType::UNDEFINED_TYPE;
}
std::string_view getTypeStr(ResourceType type) {
std::string getTypeStr(ResourceType type) {
switch (type) {
case ResourceType::BUFFER_OBJECT:
return "BufferObject";
@@ -135,8 +131,6 @@ std::string_view getTypeStr(ResourceType type) {
return "Fence";
case ResourceType::VULKAN_BUFFER:
return "VulkanBuffer";
case ResourceType::SYNC:
return "Sync";
case ResourceType::UNDEFINED_TYPE:
return "";
}
@@ -52,14 +52,13 @@ enum class ResourceType : uint8_t {
VULKAN_BUFFER = 14,
STAGE_SEGMENT = 15,
STAGE_IMAGE = 16,
SYNC = 17,
UNDEFINED_TYPE = 18, // Must be the last enum because we use it for iterating over the enums.
UNDEFINED_TYPE = 17, // Must be the last enum because we use it for iterating over the enums.
};
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;
@@ -114,9 +114,6 @@ void ResourceManager::destroyWithType(ResourceType type, HandleId id) {
case ResourceType::VULKAN_BUFFER:
destruct<VulkanBuffer>(Handle<VulkanBuffer>(id));
break;
case ResourceType::SYNC:
destruct<VulkanSync>(Handle<VulkanSync>(id));
break;
case ResourceType::UNDEFINED_TYPE:
break;
}
@@ -183,6 +183,7 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts =
ExtensionSet const TARGET_EXTS = {
// Request all cross-platform extensions.
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
// Request these if available.
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
@@ -235,6 +236,9 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
#if defined(__APPLE__)
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
#endif
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME,
VK_KHR_MULTIVIEW_EXTENSION_NAME,
};
ExtensionSet exts;
@@ -916,8 +920,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
context.mBlittableDepthStencilFormats =
findBlittableDepthStencilFormats(mImpl->mPhysicalDevice);
context.mFenceExportFlags = getFenceExportFlags();
assert_invariant(context.mDepthStencilFormats.size() > 0);
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -1000,17 +1002,6 @@ SwapChainPtr VulkanPlatform::createSwapChain(void* nativeWindow, uint64_t flags,
return swapchain;
}
Platform::Sync* VulkanPlatform::createSync(VkFence fence,
std::shared_ptr<VulkanCmdFence> fenceStatus) noexcept {
return new VulkanSync{.fence = fence, .fenceStatus = fenceStatus};
}
void VulkanPlatform::destroySync(Platform::Sync* sync) noexcept {
// Sync must be a VulkanSync*, since it was created by VulkanPlatform's
// createSync object.
delete sync;
}
VkInstance VulkanPlatform::getInstance() const noexcept {
return mImpl->mInstance;
}
@@ -1047,11 +1038,6 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
return mImpl->mProtectedGraphicsQueue;
}
VkExternalFenceHandleTypeFlagBits VulkanPlatform::getFenceExportFlags() const noexcept {
// By default, fences should not be exportable.
return static_cast<VkExternalFenceHandleTypeFlagBits>(0);
}
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
return getSwapchainInstanceExtensionsImpl();
}
@@ -389,37 +389,6 @@ VulkanPlatform::ImageData VulkanPlatformAndroid::createVkImageFromExternal(
};
}
bool VulkanPlatformAndroid::convertSyncToFd(Platform::Sync* sync, int* fd) const noexcept {
assert_invariant(sync && fd);
VulkanSync& vulkanSync = static_cast<VulkanSync&>(*sync);
assert_invariant(vulkanSync.fenceStatus);
if (vulkanSync.fenceStatus->getStatus() == VK_SUCCESS) {
// We've already signaled; return -1 so that operations will proceed
// immediately. Also, signal that fence conversion was successful.
*fd = -1;
return true;
}
VkFenceGetFdInfoKHR getFdInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR,
.fence = vulkanSync.fence,
.handleType = getFenceExportFlags(),
};
VkResult res = vkGetFenceFdKHR(getDevice(), &getFdInfo, fd);
if (res != VK_SUCCESS) {
LOG(ERROR) << "Failed to convert sync to fd: " << res;
return false;
}
return true;
}
VkExternalFenceHandleTypeFlagBits VulkanPlatformAndroid::getFenceExportFlags() const noexcept {
// On android, make fences that can be exported to fd's.
return VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
}
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
return {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
@@ -28,8 +28,8 @@
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
#ifndef VK_EXT_metal_surface
#error VK_EXT_metal_surface is not defined
#ifndef VK_MVK_macos_surface
#error VK_MVK_macos_surface is not defined
#endif
using namespace bluevk;
@@ -38,7 +38,7 @@ namespace filament::backend {
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
ExtensionSet const ret = {
VK_EXT_METAL_SURFACE_EXTENSION_NAME,
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
};
return ret;
}
@@ -46,18 +46,17 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface;
CAMetalLayer* mlayer = (__bridge CAMetalLayer*) nativeWindow;
FILAMENT_CHECK_POSTCONDITION(mlayer) << "Unable to obtain Metal-backed layer.";
NSView* nsview = (__bridge NSView*) nativeWindow;
FILAMENT_CHECK_POSTCONDITION(nsview) << "Unable to obtain Metal-backed NSView.";
// Create the VkSurface.
FILAMENT_CHECK_POSTCONDITION(vkCreateMetalSurfaceEXT)
<< "Unable to load vkCreateMetalSurfaceEXT.";
VkMetalSurfaceCreateInfoEXT createInfo = {
.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
.pLayer = mlayer,
};
VkResult result =
vkCreateMetalSurfaceEXT(instance, &createInfo, VKALLOC, &surface);
FILAMENT_CHECK_POSTCONDITION(vkCreateMacOSSurfaceMVK)
<< "Unable to load vkCreateMacOSSurfaceMVK.";
VkMacOSSurfaceCreateInfoMVK createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
createInfo.pView = (__bridge void*) nsview;
VkResult result = vkCreateMacOSSurfaceMVK((VkInstance) instance, &createInfo, VKALLOC,
(VkSurfaceKHR*) &surface);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateMacOSSurfaceMVK. error=" << static_cast<int32_t>(result);
return std::make_tuple(surface, VkExtent2D{});
File diff suppressed because it is too large Load Diff
+45 -95
View File
@@ -28,7 +28,6 @@
#include "WebGPURenderTarget.h"
#include "WebGPUStrings.h"
#include "WebGPUSwapChain.h"
#include "WebGPUSync.h"
#include "WebGPUTexture.h"
#include "WebGPUTextureHelpers.h"
#include "WebGPUVertexBuffer.h"
@@ -155,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,
@@ -209,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;
@@ -237,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) {
@@ -378,10 +367,6 @@ Handle<HwFence> WebGPUDriver::createFenceS() noexcept {
return allocAndConstructHandle<WebGPUFence, HwFence>();
}
Handle<HwSync> WebGPUDriver::createSyncS() noexcept {
return allocHandle<WebGPUSync>();
}
Handle<HwTimerQuery> WebGPUDriver::createTimerQueryS() noexcept {
return Handle<HwTimerQuery>((Handle<HwTimerQuery>::HandleId) mNextFakeHandle++);
}
@@ -450,11 +435,8 @@ 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();
// TODO: support MSAA swapchain
mNativeWindow = nativeWindow;
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
@@ -475,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);
@@ -488,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 "
@@ -560,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");
}
@@ -585,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);
@@ -614,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,
@@ -647,49 +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::createSyncR(Handle<HwSync> syncHandle, utils::CString tag) {
// TODO: Ensure sync is active, and then invoke and clear all pending
// callbacks.
setDebugTag(syncHandle.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
};
@@ -732,18 +698,6 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fenceHandle) {
return fence->getStatus();
}
void WebGPUDriver::destroySync(Handle<HwSync> syncHandle) {
if (syncHandle) {
destructHandle<WebGPUSync>(syncHandle);
}
}
void WebGPUDriver::getPlatformSync(Handle<HwSync> syncHandle, CallbackHandler* handler,
Platform::SyncCallback cb, void* userData) {
// TODO: If the sync has been inserted into the command stream, execute
// the callback. Otherwise, enqueue it.
}
bool WebGPUDriver::isTextureFormatSupported(const TextureFormat format) {
return toWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
}
@@ -793,10 +747,6 @@ bool WebGPUDriver::isSRGBSwapChainSupported() {
return false;
}
bool WebGPUDriver::isMSAASwapChainSupported(uint32_t) {
return false;
}
bool WebGPUDriver::isProtectedContentSupported() {
return false;
}
@@ -1403,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;
}
@@ -1437,7 +1387,7 @@ void WebGPUDriver::commit(Handle<HwSwapChain> swapChainHandle) {
}
mTextureView = nullptr;
assert_invariant(mSwapChain);
mSwapChain->present(*this);
mSwapChain->present();
}
void WebGPUDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
@@ -68,7 +68,6 @@ private:
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
void setDebugTag(HandleBase::HandleId handleId, utils::CString tag);
// The platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
// handled in the WebGPUPlatform.
@@ -293,11 +293,10 @@ wgpu::RenderPipeline WebGPUPipelineCache::createRenderPipeline(
},
.primitive = {
.topology = toWebGPU(request.primitiveType),
// TODO This won't always be the case for the primitives bound. But this particular field
// in the pipeline struct is only meant for restarting the strip, which we don't need so far.
.stripIndexFormat =
isStripPrimitiveType(request.primitiveType)? wgpu::IndexFormat::Uint16 :
wgpu::IndexFormat::Undefined,
// TODO should we assume some constant format here or is there a way to get
// this from PipelineState somehow or elsewhere?
// Perhaps, cache/assert format from index buffers as they are requested?
.stripIndexFormat = wgpu::IndexFormat::Undefined,
.frontFace = request.rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
.cullMode = toWebGPU(request.rasterState.culling),
// TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
@@ -313,10 +312,12 @@ wgpu::RenderPipeline WebGPUPipelineCache::createRenderPipeline(
},
.fragment = nullptr // will add below if fragment module is included
};
FILAMENT_CHECK_POSTCONDITION(!isStripPrimitiveType(request.primitiveType) ||
pipelineDescriptor.primitive.stripIndexFormat != wgpu::IndexFormat::Undefined)
<< "If the topology is a strip format, e.g. TriangleStrip, the stripIndexFormat cannot "
"be Undefined.";
// TODO:
if (pipelineDescriptor.primitive.topology == wgpu::PrimitiveTopology::LineStrip ||
pipelineDescriptor.primitive.topology == wgpu::PrimitiveTopology::TriangleStrip) {
PANIC_POSTCONDITION("stripIndexFormat must be set for strip topologies. "
"This needs to be plumbed through from the RenderPrimitive.");
}
wgpu::FragmentState fragmentState = {};
const wgpu::BlendState blendState {
@@ -161,7 +161,7 @@ private:
// render targets... //
uint8_t multisampleCount{ 0 }; // 1 : 313
uint8_t colorFormatCount{ 0 }; // 1 : 314
uint8_t padding[5]{ 0 }; // 5 : 315
uint8_t padding[5]{ 0 }; // 5 : 319
TargetBufferFlags targetRenderFlags{ TargetBufferFlags::NONE }; // 4 : 320
wgpu::TextureFormat depthStencilFormat { wgpu::TextureFormat::Undefined }; // 4 : 324
wgpu::TextureFormat colorFormats[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]{ //
@@ -386,17 +386,10 @@ wgpu::Texture WebGPUSwapChain::getCurrentTexture() {
}
void WebGPUSwapChain::present(DriverBase& driver) {
void WebGPUSwapChain::present() {
if (!isHeadless()) {
mSurface.Present();
}
if (frameScheduled.callback) {
driver.scheduleCallback(frameScheduled.handler,
[callback = std::move(frameScheduled.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback(noop);
});
}
}
}// namespace filament::backend
+1 -11
View File
@@ -49,12 +49,7 @@ public:
[[nodiscard]] bool isHeadless() const { return mType == SwapChainType::HEADLESS; }
void present(DriverBase& driver);
void setFrameScheduledCallback(CallbackHandler* handler, FrameScheduledCallback&& callback) {
frameScheduled.handler = handler;
frameScheduled.callback = std::move(callback);
}
void present();
private:
@@ -80,11 +75,6 @@ private:
uint8_t mHeadlessBufferIndex = 0;
std::array<wgpu::Texture, mHeadlessBufferCount> mRenderTargetTextures;
std::array<wgpu::TextureView, mHeadlessBufferCount> mRenderTargetViews;
struct {
CallbackHandler* handler = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
};
} // namespace filament::backend
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_WEBGPUSYNC_H
#define TNT_FILAMENT_BACKEND_WEBGPUSYNC_H
#include "DriverBase.h"
namespace filament::backend {
// TODO: provide a more complete implementation of Sync.
class WebGPUSync final : public HwSync {
};
}
#endif // TNT_FILAMENT_BACKEND_WEBGPUSYNC_H
+18 -44
View File
@@ -216,9 +216,7 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
mBlockWidth{ filament::backend::getBlockWidth(format) },
mBlockHeight{ filament::backend::getBlockHeight(format) },
mDefaultMipLevel{ 0 },
mDefaultBaseArrayLayer{ 0 },
// an undefined mSwizzle means that is not a swizzle view
mSwizzle{} {
mDefaultBaseArrayLayer{ 0 } {
assert_invariant(
samples == 1 ||
samples == 4 &&
@@ -281,36 +279,11 @@ WebGPUTexture::WebGPUTexture(WebGPUTexture const* src, const uint8_t baseLevel,
mTexture{ src->mTexture },
mDefaultMipLevel{ baseLevel },
mDefaultBaseArrayLayer{ src->mArrayLayerCount },
mMsaaSidecarTexture{ src->mMsaaSidecarTexture },
mSwizzle{ src->mSwizzle } {
const bool swizzleUndefined{ (src->mSwizzle.r == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.g == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.b == wgpu::ComponentSwizzle::Undefined) &&
(src->mSwizzle.a == wgpu::ComponentSwizzle::Undefined) };
if (swizzleUndefined) {
mDefaultTextureView = makeTextureView(mDefaultMipLevel, levelCount, 0,
mDefaultBaseArrayLayer, src->getViewDimension());
} else {
wgpu::TextureComponentSwizzleDescriptor swizzleDesc{};
swizzleDesc.swizzle = mSwizzle;
const wgpu::TextureViewDescriptor viewDesc{
.nextInChain = &swizzleDesc,
.label = "swizzled_texture_view",
.format = mTexture.GetFormat(),
.dimension = src->getViewDimension(),
.baseMipLevel = mDefaultMipLevel,
.mipLevelCount = levelCount,
.baseArrayLayer = 0,
.arrayLayerCount = mDefaultBaseArrayLayer,
};
mDefaultTextureView = mTexture.CreateView(&viewDesc);
FILAMENT_CHECK_POSTCONDITION(mDefaultTextureView)
<< "Failed to create swizzled Texture view";
}
}
mDefaultTextureView{ makeTextureView(mDefaultMipLevel, levelCount, 0, mDefaultBaseArrayLayer,
toWebGPUTextureViewDimension(src->target)) },
mMsaaSidecarTexture{ src->mMsaaSidecarTexture } {}
WebGPUTexture::WebGPUTexture(const WebGPUTexture* src,
const wgpu::TextureComponentSwizzle nextSwizzle) noexcept
WebGPUTexture::WebGPUTexture(const WebGPUTexture* src, const wgpu::TextureView view) noexcept
: HwTexture{ src->target, src->levels, src->samples, src->width, src->height, src->depth,
src->format, src->usage},
mViewFormat{ src->mViewFormat },
@@ -325,19 +298,20 @@ WebGPUTexture::WebGPUTexture(const WebGPUTexture* src,
mTexture{ src->mTexture },
mDefaultMipLevel{ src->mDefaultMipLevel },
mDefaultBaseArrayLayer{ 0 },
mMsaaSidecarTexture{src->mMsaaSidecarTexture},
mSwizzle{ composeSwizzle(src->getSwizzle(), nextSwizzle) } {
wgpu::TextureComponentSwizzleDescriptor swizzleDesc{};
swizzleDesc.swizzle = mSwizzle;
mDefaultTextureView{ view },
mMsaaSidecarTexture{src->mMsaaSidecarTexture}{}
const wgpu::TextureViewDescriptor viewDesc{
.nextInChain = &swizzleDesc,
.label = "swizzled_texture_view",
.format = mTexture.GetFormat(),
.dimension = src->getViewDimension(),
};
mDefaultTextureView = mTexture.CreateView(&viewDesc);
FILAMENT_CHECK_POSTCONDITION(mDefaultTextureView) << "Failed to create swizzled Texture view";
wgpu::Texture const& WebGPUTexture::getMsaaSidecarTexture(const uint8_t sampleCount) const {
if (mMsaaSidecarTexture == nullptr) {
return mMsaaSidecarTexture; // nullptr (no such sidecar)
}
FILAMENT_CHECK_PRECONDITION(sampleCount == mMsaaSidecarTexture.GetSampleCount())
<< "The MSAA sidecar texture has a different sample count ("
<< mMsaaSidecarTexture.GetSampleCount() << ") than requested (" << +sampleCount
<< "). Note that this restriction was written when WebGPU only supported msaa "
"textures with 4 samples. If that has changed, this implementation should be "
"updated (e.g. map of sidecar textures by sampleCount or something).";
return mMsaaSidecarTexture;
}
bool WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(const wgpu::TextureFormat format) {

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