From 075743ef59cbfbc001477bae8ee0a4b7e24c93fc Mon Sep 17 00:00:00 2001 From: Doris Wu Date: Thu, 6 Mar 2025 10:08:55 +0800 Subject: [PATCH 01/21] Aggregate the subresource usage when collapsed (#8492) --- libs/fgviewer/web/app.js | 72 ++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/libs/fgviewer/web/app.js b/libs/fgviewer/web/app.js index 3ab55adc81..758cb04032 100644 --- a/libs/fgviewer/web/app.js +++ b/libs/fgviewer/web/app.js @@ -293,11 +293,6 @@ class FrameGraphTable extends LitElement { margin-right: 5px; user-select: none; } - - .hidden { - display: none; - } - .scrollable-table td, .scrollable-table th { padding: 12px; @@ -351,6 +346,7 @@ class FrameGraphTable extends LitElement { super(); this.frameGraphData = null; this.selectedResourceId = -1; + this.collapsedResources = new Set(); } updated(props) { @@ -369,11 +365,13 @@ class FrameGraphTable extends LitElement { } _toggleCollapse(resourceIndex) { - const subresourceRows = this.shadowRoot.querySelectorAll(`[id^="subresource-${resourceIndex}-"]`); - const icon = this.shadowRoot.querySelector(`#resource-${resourceIndex} .toggle-icon`); - const isHidden = subresourceRows[0]?.classList.contains('hidden'); - subresourceRows.forEach(row => row.classList.toggle('hidden')); - icon.textContent = isHidden ? '▼' : '▶'; + if (this.collapsedResources.has(resourceIndex)) { + this.collapsedResources.delete(resourceIndex); + } + else { + this.collapsedResources.add(resourceIndex); + } + this.requestUpdate(); } _handleResourceClick(ev) { @@ -384,13 +382,16 @@ class FrameGraphTable extends LitElement { })); } - _renderResourceUsage(allPasses, resourceId, defaultColor) { + _renderResourceUsage(allPasses, resourceIds, defaultColor) { return allPasses.map((passData, index) => { - const isRead = passData?.reads.includes(resourceId); - const isWrite = passData?.writes.includes(resourceId); + const isRead = resourceIds.some(resourceId => passData?.reads.includes(resourceId)); + const isWrite = resourceIds.some(resourceId => passData?.writes.includes(resourceId)); let type = null; + const hasUsed = (passData) => { - return passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId); + return resourceIds.some(resourceId => + passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId) + ); }; const hasBeenUsedBefore = allPasses.slice(0, index).some(hasUsed); const willBeUsedLater = allPasses.slice(index + 1).some(hasUsed); @@ -399,6 +400,7 @@ class FrameGraphTable extends LitElement { else if (isRead) type = RESOURCE_USAGE_TYPE_READ; else if (isWrite) type = RESOURCE_USAGE_TYPE_WRITE; else if (hasBeenUsedBefore && willBeUsedLater) type = RESOURCE_USAGE_TYPE_NO_ACCESS; + return html` ${type ?? nothing} @@ -423,24 +425,38 @@ class FrameGraphTable extends LitElement { } _renderResourceRow(resource, resourceIndex, resources, allPasses) { - const hasSubresources = resources.some(subresource => this._isSubresourceOfParent(subresource, resource)); + const subresourceIds = resources + .filter(subresource => this._isSubresourceOfParent(subresource, resource)) + .map(subresource => subresource.id); + + const hasSubresources = subresourceIds.length > 0; + const isCollapsed = this.collapsedResources.has(resourceIndex); + // Show the aggregated resource usage when the subresources are collapsed. + const resourceIds = isCollapsed ? [resource.id, ...subresourceIds]:[resource.id]; + const onClickResource = () => this._handleResourceClick(resource.id); const selectedStyle = resource.id === this.selectedResourceId ? "selected" : ""; return html` - - - ${hasSubresources ? html` - ▶` : nothing} - ${resource.name} - - ${this._renderResourceUsage(allPasses, resource.id, DEFAULT_COLOR)} - - ${this._renderSubresourceRows(resources, resource, resourceIndex, allPasses)} - `; + + + ${hasSubresources + ? html` + + ${isCollapsed ? '▶' : '▼'} + ` + : nothing} + ${resource.name} + ${hasSubresources && isCollapsed ? html`(${subresourceIds.length})` : nothing} + + ${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)} + + ${!isCollapsed ? this._renderSubresourceRows(resources, resource, resourceIndex, allPasses) : nothing} + `; } + _renderSubresourceRows(resources, parentResource, resourceIndex, allPasses) { return resources .filter(subresource => this._isSubresourceOfParent(subresource, parentResource)) @@ -452,13 +468,13 @@ class FrameGraphTable extends LitElement { const selectedStyle = subresource.id === this.selectedResourceId ? "selected" : ""; return html` - + ${subresource.name} - ${this._renderResourceUsage(allPasses, subresource.id, SUBRESOURCE_COLOR)} + ${this._renderResourceUsage(allPasses, [subresource.id], SUBRESOURCE_COLOR)} `; } From d9e30460dc24f75dc083d9e4c884bddc8f5b6187 Mon Sep 17 00:00:00 2001 From: Doris Wu Date: Thu, 6 Mar 2025 13:36:41 +0800 Subject: [PATCH 02/21] Enable fgviewer for android remote debugging (#8483) * Enable fgviewer for the users * Fix incorrect position * Update * Support remote debug server * Enable fgviewer on android * Link and include fgviewer_resources * Adjust js to show untitled view --- android/build.gradle | 10 +++--- android/filament-android/CMakeLists.txt | 17 ++++------ android/gradle.properties | 1 + libs/fgviewer/CMakeLists.txt | 38 ++++++++++++++++++++-- libs/fgviewer/src/DebugServer.cpp | 43 +++++++++++++++++++++++++ libs/fgviewer/web/app.js | 2 +- 6 files changed, 91 insertions(+), 20 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 5cbd9c33be..c2c3e5fed6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -71,10 +71,9 @@ buildscript { .gradleProperty("com.google.android.filament.include-webgpu") .isPresent() - // TODO: Uncomment below when fgviewer is ready - // def fgviewer = providers - // .gradleProperty("com.google.android.filament.fgviewer") - // .isPresent() + def fgviewer = providers + .gradleProperty("com.google.android.filament.fgviewer") + .isPresent() def matdbg = providers .gradleProperty("com.google.android.filament.matdbg") @@ -131,8 +130,7 @@ buildscript { "-DFILAMENT_DIST_DIR=${filamentPath}".toString(), "-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(), "-DFILAMENT_SUPPORTS_WEBGPU=${includeWebGPU ? 'ON' : 'OFF'}".toString(), - // TODO: Uncomment below when fgviewer is ready - // "-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(), + "-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(), "-DFILAMENT_ENABLE_MATDBG=${matdbg ? 'ON' : 'OFF'}".toString(), "-DFILAMENT_DISABLE_MATOPT=${matnopt ? 'ON' : 'OFF'}".toString() ] diff --git a/android/filament-android/CMakeLists.txt b/android/filament-android/CMakeLists.txt index 2b4c91add7..59bcb32335 100644 --- a/android/filament-android/CMakeLists.txt +++ b/android/filament-android/CMakeLists.txt @@ -2,8 +2,7 @@ cmake_minimum_required(VERSION 3.19) project(filament-android) option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF) -# TODO: Uncomment below when fgviewer is ready -# option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" 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) @@ -60,12 +59,11 @@ add_library(smol-v STATIC IMPORTED) set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a) -# TODO: Uncomment below when fgviewer is ready -# if (FILAMENT_ENABLE_FGVIEWER) -# add_library(fgviewer STATIC IMPORTED) -# set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION -# ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a) -# endif() + if (FILAMENT_ENABLE_FGVIEWER) + add_library(fgviewer STATIC IMPORTED) + set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION + ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a) + endif() if (FILAMENT_ENABLE_MATDBG) add_library(matdbg STATIC IMPORTED) @@ -133,8 +131,7 @@ target_link_libraries(filament-jni # libgeometry is PUBLIC because gltfio uses it. PUBLIC geometry - # TODO: Uncomment below when fgviewer is ready - # $<$:fgviewer> + $<$:fgviewer> $<$:matdbg> $<$:filamat> $<$:bluevk> diff --git a/android/gradle.properties b/android/gradle.properties index 80a78466d9..e482e6fd0b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -30,4 +30,5 @@ com.google.android.filament.abis=all #com.google.android.filament.include-webgpu #com.google.android.filament.matdbg +#com.google.android.filament.fgviewer #com.google.android.filament.matnopt diff --git a/libs/fgviewer/CMakeLists.txt b/libs/fgviewer/CMakeLists.txt index 559c975408..9f2ccc4c4b 100644 --- a/libs/fgviewer/CMakeLists.txt +++ b/libs/fgviewer/CMakeLists.txt @@ -26,16 +26,47 @@ set(SRCS src/JsonWriter.cpp ) +# ================================================================================================== +# Resources +# ================================================================================================== + +set(RESOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +set(RESOURCE_BINS + ${CMAKE_CURRENT_SOURCE_DIR}/web/api.js + ${CMAKE_CURRENT_SOURCE_DIR}/web/app.js + ${CMAKE_CURRENT_SOURCE_DIR}/web/index.html +) + +get_resgen_vars(${RESOURCE_DIR} fgviewer_resources) + +add_custom_command( + OUTPUT ${RESGEN_OUTPUTS} + COMMAND resgen -t ${RESGEN_FLAGS} ${RESOURCE_BINS} + DEPENDS resgen ${RESOURCE_BINS} +) + +if (DEFINED RESGEN_SOURCE_FLAGS) + set_source_files_properties(${RESGEN_SOURCE} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS}) +endif() + +set(DUMMY_SRC "${RESOURCE_DIR}/dummy.c") +add_custom_command(OUTPUT ${DUMMY_SRC} COMMAND echo "//" > ${DUMMY_SRC}) + +add_library(fgviewer_resources ${DUMMY_SRC} ${RESGEN_SOURCE}) +set_target_properties(fgviewer_resources PROPERTIES FOLDER Libs) + # ================================================================================================== # Include and target definitions # ================================================================================================== -include_directories(${PUBLIC_HDR_DIR}) +include_directories(${PUBLIC_HDR_DIR} ${RESOURCE_DIR}) add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS}) target_link_libraries(${TARGET} PUBLIC civetweb + fgviewer_resources utils ) @@ -57,11 +88,12 @@ endif() # Installation # ================================================================================================== -# matdbg has dependencies on non-installed libraries. Here we bundle them all together into a single +# fgviewer has dependencies on non-installed libraries. Here we bundle them all together into a single # library that gets copied into the installation folder so users are only required to link against -# matdbg. +# fgviewer. set(FGVIEWER_DEPS fgviewer + fgviewer_resources civetweb ) diff --git a/libs/fgviewer/src/DebugServer.cpp b/libs/fgviewer/src/DebugServer.cpp index 268b410d22..a68413bdad 100644 --- a/libs/fgviewer/src/DebugServer.cpp +++ b/libs/fgviewer/src/DebugServer.cpp @@ -30,9 +30,26 @@ namespace filament::fgviewer { +// If set to 0, this serves HTML from a resgen resource. Use 1 only during local development, which +// serves files directly from the source code tree. +#define SERVE_FROM_SOURCE_TREE 0 + +#if SERVE_FROM_SOURCE_TREE namespace { std::string const BASE_URL = "libs/fgviewer/web"; } // anonymous +#else +#include "fgviewer_resources.h" +#include + +namespace { +struct Asset { + std::string_view mime; + std::string_view data; +}; +std::unordered_map ASSET_MAP; +} // anonymous +#endif // SERVE_FROM_SOURCE_TREE using namespace utils; @@ -56,10 +73,21 @@ public: uri = "/index.html"; } +#if SERVE_FROM_SOURCE_TREE if (uri == "/index.html" || uri == "/app.js" || uri == "/api.js") { mg_send_file(conn, (BASE_URL + uri).c_str()); return true; } +#else + auto const& asset_itr = ASSET_MAP.find(uri); + if (asset_itr != ASSET_MAP.end()) { + auto const& mime = asset_itr->second.mime; + auto const& data = asset_itr->second.data; + mg_printf(conn, kSuccessHeader.data(), mime.data()); + mg_write(conn, data.data(), data.size()); + return true; + } +#endif slog.e << "[fgviewer] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl; return false; } @@ -68,6 +96,21 @@ private: }; DebugServer::DebugServer(int port) { +#if !SERVE_FROM_SOURCE_TREE + ASSET_MAP["/index.html"] = { + .mime = "text/html", + .data = {(char const*) FGVIEWER_RESOURCES_INDEX_DATA}, + }; + ASSET_MAP["/app.js"] = { + .mime = "text/javascript", + .data = {(char const*) FGVIEWER_RESOURCES_APP_DATA}, + }; + ASSET_MAP["/api.js"] = { + .mime = "text/javascript", + .data = {(char const*) FGVIEWER_RESOURCES_API_DATA}, + }; +#endif + // By default the server spawns 50 threads so we override this to 10. According to the civetweb // documentation, "it is recommended to use num_threads of at least 5, since browsers often /// establish multiple connections to load a single web page, including all linked documents diff --git a/libs/fgviewer/web/app.js b/libs/fgviewer/web/app.js index 758cb04032..115cbffdf7 100644 --- a/libs/fgviewer/web/app.js +++ b/libs/fgviewer/web/app.js @@ -16,7 +16,7 @@ import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module"; -const kUntitledPlaceholder = "untitled"; +const kUntitledPlaceholder = "Untitled View"; // CSS constants const FOREGROUND_COLOR = '#fafafa'; From 30bb4ad6eb06d5fda973a68930d781bf44e3577e Mon Sep 17 00:00:00 2001 From: HanYunChenLuo Date: Fri, 7 Mar 2025 01:22:29 +0800 Subject: [PATCH 03/21] fix SourceFormatter.h missing header file (#8498) missing --- libs/matdbg/src/SourceFormatter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/matdbg/src/SourceFormatter.h b/libs/matdbg/src/SourceFormatter.h index 5793474d71..21fbe8f329 100644 --- a/libs/matdbg/src/SourceFormatter.h +++ b/libs/matdbg/src/SourceFormatter.h @@ -18,6 +18,7 @@ #define MATDBG_SOURCE_FORMATTER_H #include +#include namespace filament::matdbg { From 47112f136e8be2c1c4b8a5c17fe0a2ddfd223fad Mon Sep 17 00:00:00 2001 From: Ajmal Kunnummal Date: Thu, 6 Mar 2025 10:23:06 -0800 Subject: [PATCH 04/21] Add a way to query the transform matrix of a surface texture from the driver (#8489) * Add a way to query the transform matrix of a surface texture from the driver BUGS=[399959254] --- .../backend/platforms/OpenGLPlatform.h | 8 +++++++ .../backend/platforms/PlatformEGLAndroid.h | 1 + filament/backend/src/opengl/OpenGLDriver.cpp | 9 ++++++++ filament/backend/src/opengl/OpenGLDriver.h | 1 + .../backend/src/opengl/OpenGLPlatform.cpp | 4 ++++ .../ExternalStreamManagerAndroid.cpp | 23 +++++++++++++++++++ .../platforms/ExternalStreamManagerAndroid.h | 5 ++++ .../opengl/platforms/PlatformEGLAndroid.cpp | 4 ++++ 8 files changed, 55 insertions(+) diff --git a/filament/backend/include/backend/platforms/OpenGLPlatform.h b/filament/backend/include/backend/platforms/OpenGLPlatform.h index a64278dab2..121039ea31 100644 --- a/filament/backend/include/backend/platforms/OpenGLPlatform.h +++ b/filament/backend/include/backend/platforms/OpenGLPlatform.h @@ -27,6 +27,7 @@ #include #include +#include namespace filament::backend { @@ -319,6 +320,13 @@ public: virtual void updateTexImage(Stream* UTILS_NONNULL stream, int64_t* UTILS_NONNULL timestamp) noexcept; + /** + * Returns the transform matrix of the texture attached to the stream. + * @param stream Stream to get the transform matrix from + * @param uvTransform Output parameter: Transform matrix of the image bound to the texture. Returns identity if not supported. + */ + virtual math::mat3f getTransformMatrix(Stream* UTILS_NONNULL stream) noexcept; + // -------------------------------------------------------------------------------------------- // External Image support diff --git a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h index b56d30880b..ecd8fc8ab4 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h +++ b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h @@ -86,6 +86,7 @@ protected: void attach(Stream* stream, intptr_t tname) noexcept override; void detach(Stream* stream) noexcept override; void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override; + math::mat3f getTransformMatrix(Stream* stream) noexcept override; /** * Converts a AHardwareBuffer to EGLImage diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 81436e4dc9..6f79963cac 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -58,6 +58,7 @@ #include #include +#include #include #include @@ -2163,6 +2164,14 @@ int64_t OpenGLDriver::getStreamTimestamp(Handle sh) { return 0; } +math::mat3f OpenGLDriver::getStreamTransformMatrix(Handle sh) { + if (sh) { + GLStream* s = handle_cast(sh); + return mPlatform.getTransformMatrix(s->stream); + } + return math::mat3f(); +} + void OpenGLDriver::destroyFence(Handle fh) { if (fh) { GLFence* f = handle_cast(fh); diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 5a3f8050a6..8cb735fac4 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -367,6 +367,7 @@ private: void attachStream(GLTexture* t, GLStream* stream) noexcept; void detachStream(GLTexture* t) noexcept; void replaceStream(GLTexture* t, GLStream* stream) noexcept; + math::mat3f getStreamTransformMatrix(Handle sh); #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 // tasks executed on the main thread after the fence signaled diff --git a/filament/backend/src/opengl/OpenGLPlatform.cpp b/filament/backend/src/opengl/OpenGLPlatform.cpp index 57d021cf0d..4506223aa9 100644 --- a/filament/backend/src/opengl/OpenGLPlatform.cpp +++ b/filament/backend/src/opengl/OpenGLPlatform.cpp @@ -141,6 +141,10 @@ void OpenGLPlatform::updateTexImage( UTILS_UNUSED int64_t* timestamp) noexcept { } +math::mat3f OpenGLPlatform::getTransformMatrix( + UTILS_UNUSED Stream* stream) noexcept { +return math::mat3f(); +} OpenGLPlatform::ExternalTexture* OpenGLPlatform::createExternalImageTexture() noexcept { return nullptr; diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp index 88b929d8bb..f3291c7ebb 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp @@ -38,6 +38,7 @@ typedef struct ASurfaceTexture ASurfaceTexture; #include #include +#include using namespace utils; @@ -73,6 +74,7 @@ JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept { mSurfaceTextureClass_attachToGLContext = env->GetMethodID(SurfaceTextureClass, "attachToGLContext", "(I)V"); mSurfaceTextureClass_detachFromGLContext = env->GetMethodID(SurfaceTextureClass, "detachFromGLContext", "()V"); mSurfaceTextureClass_getTimestamp = env->GetMethodID(SurfaceTextureClass, "getTimestamp", "()J"); + mSurfaceTextureClass_getTransformMatrix = env->GetMethodID(SurfaceTextureClass, "getTransformMatrix", "([F)V"); return env; } @@ -167,4 +169,25 @@ void ExternalStreamManagerAndroid::updateTexImage(Stream* handle, int64_t* times } } +math::mat3f ExternalStreamManagerAndroid::getTransformMatrix(Stream* handle) noexcept { + EGLStream const* stream = static_cast(handle); + math::mat4f out = math::mat4f(); + if (__builtin_available(android 28, *)) { + ASurfaceTexture_getTransformMatrix(stream->nSurfaceTexture, &out[0][0]); + } else { + JNIEnv* const env = getEnvironment(); + assert_invariant(env); // we should have called attach() by now + auto jout = env->NewFloatArray(16); + env->CallVoidMethod(stream->jSurfaceTexture, mSurfaceTextureClass_getTransformMatrix, jout); + env->GetFloatArrayRegion(jout, 0, 16, &out[0][0]); + env->DeleteLocalRef(jout); + VirtualMachineEnv::handleException(env); + } + return math::mat3f { + out[0][0], out[0][1], out[0][3], + out[1][0], out[1][1], out[1][3], + out[3][0], out[3][1], out[3][3], + }; +} + } // namespace filament::backend diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h index d1257269c3..610cea0ee7 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h @@ -33,6 +33,7 @@ typedef struct ASurfaceTexture ASurfaceTexture; #include #include +#include namespace filament::backend { @@ -63,6 +64,9 @@ public: // must be called on GLES context thread, updates the stream content void updateTexImage(Stream* stream, int64_t* timestamp) noexcept; + // must be called on GLES context thread, returns the transform matrix + math::mat3f getTransformMatrix(Stream* stream) noexcept; + private: ExternalStreamManagerAndroid() noexcept; ~ExternalStreamManagerAndroid() noexcept; @@ -88,6 +92,7 @@ private: jmethodID mSurfaceTextureClass_updateTexImage{}; jmethodID mSurfaceTextureClass_getTimestamp{}; + jmethodID mSurfaceTextureClass_getTransformMatrix{}; jmethodID mSurfaceTextureClass_attachToGLContext{}; jmethodID mSurfaceTextureClass_detachFromGLContext{}; }; diff --git a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp index 73828f74ca..e32adb864e 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp @@ -283,6 +283,10 @@ void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noex mExternalStreamManager.updateTexImage(stream, timestamp); } +math::mat3f PlatformEGLAndroid::getTransformMatrix(Stream* stream) noexcept { + return mExternalStreamManager.getTransformMatrix(stream); +} + int PlatformEGLAndroid::getOSVersion() const noexcept { return mOSVersion; } From 02223dcaabb59178f7de907bad29d80f02dea770 Mon Sep 17 00:00:00 2001 From: Ajmal Kunnummal Date: Thu, 6 Mar 2025 10:42:24 -0800 Subject: [PATCH 05/21] Add a way to specify an additional uniform name along with a sampler param for the associated transform matrix (#8490) BUGS=[399959254] --- NEW_RELEASE_NOTES.md | 1 + docs/Materials.md.html | 7 ++-- filament/src/MaterialParser.cpp | 6 ++++ .../private/filament/BufferInterfaceBlock.h | 33 ++++++++++++++++--- libs/filabridge/src/BufferInterfaceBlock.cpp | 21 ++++++++++-- .../filamat/include/filamat/MaterialBuilder.h | 8 +++-- libs/filamat/src/MaterialBuilder.cpp | 14 +++++--- .../src/eiff/MaterialInterfaceBlockChunk.cpp | 1 + tools/matc/src/matc/ParametersProcessor.cpp | 20 ++++++++++- 9 files changed, 93 insertions(+), 18 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..63090f0235 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,4 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut +- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**] diff --git a/docs/Materials.md.html b/docs/Materials.md.html index 753e3a6b2f..fae697661c 100644 --- a/docs/Materials.md.html +++ b/docs/Materials.md.html @@ -991,10 +991,13 @@ Type Value : Each entry is an object with the properties `name` and `type`, both of `string` type. The - name must be a valid GLSL identifier. Entries also have an optional `precision`, which can be + 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]. + 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. Type | Description :----------------------|:--------------------------------- diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index 5c5873726c..400e8e18d0 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -421,6 +421,7 @@ bool ChunkUniformInterfaceBlock::unflatten(Unflattener& unflattener, uint64_t fieldSize = 0; uint8_t fieldType = 0; uint8_t fieldPrecision = 0; + uint8_t fieldAssociatedSampler = 0; if (!unflattener.read(&fieldName)) { return false; @@ -438,8 +439,13 @@ bool ChunkUniformInterfaceBlock::unflatten(Unflattener& unflattener, return false; } + if (!unflattener.read(&fieldAssociatedSampler)) { + return false; + } + // a size of 1 means not an array builder.add({{{ fieldName.data(), fieldName.size() }, + fieldAssociatedSampler, uint32_t(fieldSize == 1 ? 0 : fieldSize), BufferInterfaceBlock::Type(fieldType), BufferInterfaceBlock::Precision(fieldPrecision) }}); diff --git a/libs/filabridge/include/private/filament/BufferInterfaceBlock.h b/libs/filabridge/include/private/filament/BufferInterfaceBlock.h index c47193208f..093326fd7a 100644 --- a/libs/filabridge/include/private/filament/BufferInterfaceBlock.h +++ b/libs/filabridge/include/private/filament/BufferInterfaceBlock.h @@ -40,11 +40,28 @@ public: std::string_view name; uint32_t size; backend::UniformType type; - backend::Precision precision{}; - backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1; - std::string_view structName{}; - uint32_t stride{}; - std::string_view sizeName{}; + backend::Precision precision; + uint8_t associatedSampler = 0; + backend::FeatureLevel minFeatureLevel; + std::string_view structName; + uint32_t stride; + std::string_view sizeName; + + InterfaceBlockEntry() = default; + InterfaceBlockEntry(std::string_view name, uint32_t size, backend::UniformType type, + backend::Precision precision = {}, + backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1, std::string_view structName = {}, + uint32_t stride = {}, std::string_view sizeName = {}) noexcept + : name(name), size(size), type(type), precision(precision), + associatedSampler(0), minFeatureLevel(minFeatureLevel), + structName(structName), stride(stride), sizeName(sizeName) {} + InterfaceBlockEntry(std::string_view name, uint8_t associatedSampler, uint32_t size, backend::UniformType type, + backend::Precision precision = {}, + backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1, std::string_view structName = {}, + uint32_t stride = {}, std::string_view sizeName = {}) noexcept + : name(name), size(size), type(type), precision(precision), + associatedSampler(associatedSampler), minFeatureLevel(minFeatureLevel), + structName(structName), stride(stride), sizeName(sizeName) {} }; BufferInterfaceBlock(); @@ -68,6 +85,7 @@ public: bool isArray; // true if the field is an array uint32_t size; // size of the array in elements, or 0 if not an array Precision precision; // precision of this field + uint8_t associatedSampler; // sampler associated with this field backend::FeatureLevel minFeatureLevel; // below this feature level, this field is not needed utils::CString structName; // name of this field structure if type is STRUCT utils::CString sizeName; // name of the size parameter in the shader @@ -152,6 +170,10 @@ public: // negative value if name doesn't exist or Panic if exceptions are enabled ssize_t getFieldOffset(std::string_view name, size_t index) const; + // returns offset in bytes of the transform matrix for the given external texture binding + // returns -1 if the field doesn't exist + ssize_t getTransformFieldOffset(uint8_t binding) const; + FieldInfo const* getFieldInfo(std::string_view name) const; bool hasField(std::string_view name) const noexcept { @@ -179,6 +201,7 @@ private: utils::CString mName; utils::FixedCapacityVector mFieldInfoList; std::unordered_map mInfoMap; + std::unordered_map mTransformOffsetMap; uint32_t mSize = 0; // size in bytes rounded to multiple of 4 Alignment mAlignment = Alignment::std140; Target mTarget = Target::UNIFORM; diff --git a/libs/filabridge/src/BufferInterfaceBlock.cpp b/libs/filabridge/src/BufferInterfaceBlock.cpp index 7b907baceb..046ea49557 100644 --- a/libs/filabridge/src/BufferInterfaceBlock.cpp +++ b/libs/filabridge/src/BufferInterfaceBlock.cpp @@ -58,7 +58,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::add( for (auto const& item : list) { mEntries.push_back({ { item.name.data(), item.name.size() }, - 0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.minFeatureLevel, + 0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.associatedSampler, item.minFeatureLevel, { item.structName.data(), item.structName.size() }, { item.sizeName.data(), item.sizeName.size() } }); @@ -71,7 +71,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::addVariableSizedAr mHasVariableSizeArray = true; mEntries.push_back({ { item.name.data(), item.name.size() }, - 0, uint8_t(item.stride), item.type, true, 0, item.precision, item.minFeatureLevel, + 0, uint8_t(item.stride), item.type, true, 0, item.precision, item.associatedSampler, item.minFeatureLevel, { item.structName.data(), item.structName.size() }, { item.sizeName.data(), item.sizeName.size() } }); @@ -122,6 +122,8 @@ BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept auto& uniformsInfoList = mFieldInfoList; + auto& transformOffsetMap = mTransformOffsetMap; + uint32_t i = 0; uint16_t offset = 0; for (auto const& e : builder.mEntries) { @@ -143,11 +145,16 @@ BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept FieldInfo& info = uniformsInfoList[i]; info = { e.name, offset, uint8_t(stride), e.type, e.isArray, e.size, - e.precision, e.minFeatureLevel, e.structName, e.sizeName }; + e.precision, e.associatedSampler, e.minFeatureLevel, e.structName, e.sizeName }; // record this uniform info infoMap[{ info.name.data(), info.name.size() }] = i; + // record the transform offset if this is an external sampler + if (e.associatedSampler != 0) { + transformOffsetMap[e.associatedSampler] = offset; + } + // advance offset to next slot offset += stride * std::max(1u, e.size); ++i; @@ -163,6 +170,14 @@ ssize_t BufferInterfaceBlock::getFieldOffset(std::string_view name, size_t index return (ssize_t)info->getBufferOffset(index); } +ssize_t BufferInterfaceBlock::getTransformFieldOffset(uint8_t binding) const { + auto pos = mTransformOffsetMap.find(binding); + if (pos == mTransformOffsetMap.end()) { + return -1; + } + return (ssize_t)pos->second; +} + BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo( std::string_view name) const { auto pos = mInfoMap.find(name); diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index 774c96f07d..c9ff548880 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -318,7 +318,8 @@ public: MaterialBuilder& parameter(const char* name, SamplerType samplerType, SamplerFormat format = SamplerFormat::FLOAT, ParameterPrecision precision = ParameterPrecision::DEFAULT, - bool multisample = false) noexcept; + bool multisample = false, + const char* transformName = "") noexcept; MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept; @@ -650,8 +651,8 @@ public: Parameter() noexcept: parameterType(INVALID) {} // Sampler - Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms) - : name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms) { } + Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms, const char* tn) + : name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms), transformName(tn) { } // Uniform Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p) @@ -669,6 +670,7 @@ public: SubpassType subpassType; SamplerFormat format; bool multisample; + utils::CString transformName; enum { INVALID, UNIFORM, diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index df745a33b8..15fba4b08b 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -279,7 +279,7 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type, MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType, - SamplerFormat format, ParameterPrecision precision, bool multisample) noexcept { + SamplerFormat format, ParameterPrecision precision, bool multisample, const char* transformName) noexcept { FILAMENT_CHECK_PRECONDITION(!multisample || (format != SamplerFormat::SHADOW && (samplerType == SamplerType::SAMPLER_2D || @@ -288,7 +288,7 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType sample " as long as type is not SHADOW"; FILAMENT_CHECK_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT) << "Too many parameters"; - mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample }; + mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample, transformName }; return *this; } @@ -609,12 +609,18 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept { SamplerInterfaceBlock::Builder sbb; BufferInterfaceBlock::Builder ibb; // sampler bindings start at 1, 0 is the ubo - for (size_t i = 0, binding = 1, c = mParameterCount; i < c; i++) { + uint16_t binding = 1; + for (size_t i = 0, c = mParameterCount; i < c; i++) { auto const& param = mParameters[i]; assert_invariant(!param.isSubpass()); if (param.isSampler()) { sbb.add({ param.name.data(), param.name.size() }, - binding++, param.samplerType, param.format, param.precision, param.multisample); + binding, param.samplerType, param.format, param.precision, param.multisample); + if (!param.transformName.empty()) { + ibb.add({{{ param.transformName.data(), param.transformName.size() }, uint8_t(binding), + 0, UniformType::MAT3, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }}); + } + binding++; } else if (param.isUniform()) { ibb.add({{{ param.name.data(), param.name.size() }, uint32_t(param.size == 1u ? 0u : param.size), param.uniformType, diff --git a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp index 2e86dca9d0..838e76d810 100644 --- a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp +++ b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp @@ -52,6 +52,7 @@ void MaterialUniformInterfaceBlockChunk::flatten(Flattener& f) { f.writeUint64(uInfo.size); f.writeUint8(static_cast(uInfo.type)); f.writeUint8(static_cast(uInfo.precision)); + f.writeUint8(static_cast(uInfo.associatedSampler)); } } diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp index 34bbc2d72a..c9b0cfbb10 100644 --- a/tools/matc/src/matc/ParametersProcessor.cpp +++ b/tools/matc/src/matc/ParametersProcessor.cpp @@ -153,6 +153,12 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json std::cerr << "parameters: name value must be STRING." << std::endl; return false; } + + const JsonishValue* transformNameValue = jsonObject.getValue("transformName"); + if (transformNameValue && transformNameValue->getType() != JsonishValue::STRING) { + std::cerr << "parameters: transformName value must be STRING." << std::endl; + return false; + } const JsonishValue* precisionValue = jsonObject.getValue("precision"); if (precisionValue) { @@ -221,7 +227,19 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json auto multisample = multiSampleValue ? multiSampleValue->toJsonBool()->getBool() : false; - builder.parameter(nameString.c_str(), type, format, precision, multisample); + if (transformNameValue) { + if (type != MaterialBuilder::SamplerType::SAMPLER_EXTERNAL) { + std::cerr << "parameters: the parameter with name '" << nameString << "'" + << " is a sampler of type " << typeString << " and has a transformName." + << " Transform names are only supported for external samplers." + << std::endl; + return false; + } + auto transformName = transformNameValue->toJsonString()->getString(); + builder.parameter(nameString.c_str(), type, format, precision, multisample, transformName.c_str()); + } else { + builder.parameter(nameString.c_str(), type, format, precision, multisample); + } } else { std::cerr << "parameters: the type '" << typeString From 31e966f63fbc0963e8b365644364d05226592908 Mon Sep 17 00:00:00 2001 From: bridgewaterrobbie Date: Thu, 27 Feb 2025 17:36:14 -0500 Subject: [PATCH 06/21] Add initial Tint support for shader transpile Early version that will allow errors to be ignored currently, outputting what we can into filamat results. --- libs/filamat/CMakeLists.txt | 4 ++ libs/filamat/src/GLSLPostProcessor.cpp | 58 +++++++++++++++++++++++++- libs/filamat/src/GLSLPostProcessor.h | 6 ++- libs/filamat/src/MaterialBuilder.cpp | 5 ++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/libs/filamat/CMakeLists.txt b/libs/filamat/CMakeLists.txt index 43ab29e5cc..ef30612ae1 100644 --- a/libs/filamat/CMakeLists.txt +++ b/libs/filamat/CMakeLists.txt @@ -85,6 +85,10 @@ target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR}) set_target_properties(${TARGET} PROPERTIES FOLDER Libs) target_link_libraries(${TARGET} backend_headers shaders filabridge utils smol-v) +if (FILAMENT_SUPPORTS_WEBGPU) + target_link_libraries(${TARGET} libtint) +endif () + # We are being naughty and accessing private headers here # For spirv-tools, we're just following glslang's example target_include_directories(${TARGET} PRIVATE ${spirv-tools_SOURCE_DIR}/include) diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index 8d38ed7cc2..a76a5c83f0 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -44,6 +44,10 @@ #include #include +#ifdef FILAMENT_SUPPORTS_WEBGPU +#include +#endif + using namespace glslang; using namespace spirv_cross; using namespace spvtools; @@ -514,8 +518,43 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl, } } +bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) { +#ifdef FILAMENT_SUPPORTS_WEBGPU + //Currently no options we want to use + const tint::spirv::reader::Options readerOpts{}; + tint::wgsl::writer::Options writerOpts{}; + + tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts); + + if (tintRead.Diagnostics().ContainsErrors()) { + slog.w << "This tint reader error is currently ignored during WebGPU bringup:" << tintRead.Diagnostics().Str() << io::endl; + + //TODO: We should actually return false here, but for initial debugging + // let it slide until combined image sampler is resolved + // return false; + } + + tint::Result wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts); + /// An instance of SuccessType that can be used to check a tint Result. + tint::SuccessType tintSuccess; + + if (wgslOut != tintSuccess) { + slog.w << "This tint writer error is currently ignored during WebGPU bringup:" << wgslOut.Failure().reason.Str() << io::endl; + //TODO: We should actually return false here, but for initial debugging + // let it slide until combined image sampler is resolved + // return false; + } + *outWsl = wgslOut->wgsl; + return true; +#else + slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU" << io::endl; + return false; +#endif + +} + bool GLSLPostProcessor::process(const std::string& inputShader, Config const& config, - std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl) { + std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl, std::string* outputWgsl) { using TargetLanguage = MaterialBuilder::TargetLanguage; if (config.targetLanguage == TargetLanguage::GLSL) { @@ -530,6 +569,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co .glslOutput = outputGlsl, .spirvOutput = outputSpirv, .mslOutput = outputMsl, + .wgslOutput = outputWgsl, }; switch (config.shaderType) { @@ -610,6 +650,11 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co config.shaderType, config.shaderModel, config.hasFramebufferFetch, descriptors, mGenerateDebugInfo ? &internalConfig.minifier : nullptr); } + if (internalConfig.wgslOutput) { + if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) { + return false; + } + } } else { slog.e << "GLSL post-processor invoked with optimization level NONE" << io::endl; @@ -702,6 +747,12 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, config.shaderModel, config.hasFramebufferFetch, descriptors, mGenerateDebugInfo ? &internalConfig.minifier : nullptr); } + if (internalConfig.wgslOutput) { + if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) { + return; + } + } + if (internalConfig.glslOutput) { *internalConfig.glslOutput = glsl; @@ -746,6 +797,11 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader, config.hasFramebufferFetch, descriptors, mGenerateDebugInfo ? &internalConfig.minifier : nullptr); } + if (internalConfig.wgslOutput) { + if (!spirvToWgsl(&spirv, internalConfig.wgslOutput)) { + return false; + } + } // Transpile back to GLSL if (internalConfig.glslOutput) { diff --git a/libs/filamat/src/GLSLPostProcessor.h b/libs/filamat/src/GLSLPostProcessor.h index 8616d0e4dc..70051d21a6 100644 --- a/libs/filamat/src/GLSLPostProcessor.h +++ b/libs/filamat/src/GLSLPostProcessor.h @@ -81,7 +81,8 @@ public: bool process(const std::string& inputShader, Config const& config, std::string* outputGlsl, SpirvBlob* outputSpirv, - std::string* outputMsl); + std::string* outputMsl, + std::string* outputWgsl); // public so backend_test can also use it static void spirvToMsl(const SpirvBlob* spirv, std::string* outMsl, @@ -89,11 +90,14 @@ public: bool useFramebufferFetch, const DescriptorSets& descriptorSets, const ShaderMinifier* minifier); + static bool spirvToWgsl(const SpirvBlob* spirv, std::string* outWsl); + private: struct InternalConfig { std::string* glslOutput = nullptr; SpirvBlob* spirvOutput = nullptr; std::string* mslOutput = nullptr; + std::string* wgslOutput = nullptr; EShLanguage shLang = EShLangFragment; // use 100 for ES environment, 110 for desktop int langVersion = 0; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 15fba4b08b..300ebd7cfc 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -909,6 +909,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector spirv; std::string msl; + std::string wgsl; std::vector* pSpirv = targetApiNeedsSpirv ? &spirv : nullptr; std::string* pMsl = targetApiNeedsMsl ? &msl : nullptr; + std::string* pWgsl = targetApiNeedsWgsl ? &wgsl : nullptr; TextEntry glslEntry{}; BinaryEntry spirvEntry{}; @@ -1006,7 +1009,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector Date: Thu, 27 Feb 2025 17:40:03 -0500 Subject: [PATCH 07/21] When preprocess fails, return false from process --- libs/filamat/src/GLSLPostProcessor.cpp | 11 ++++++++--- libs/filamat/src/GLSLPostProcessor.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index a76a5c83f0..2f6bbea80d 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -661,7 +661,9 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co } break; case MaterialBuilder::Optimization::PREPROCESSOR: - preprocessOptimization(tShader, config, internalConfig); + if (!preprocessOptimization(tShader, config, internalConfig)) { + return false; + } break; case MaterialBuilder::Optimization::SIZE: case MaterialBuilder::Optimization::PERFORMANCE: @@ -691,7 +693,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co return true; } -void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, +bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const { using TargetApi = MaterialBuilder::TargetApi; assert_invariant(bool(internalConfig.spirvOutput) == (config.targetApi != TargetApi::OPENGL)); @@ -707,6 +709,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, if (!ok) { slog.e << tShader.getInfoLog() << io::endl; + return false; } if (internalConfig.spirvOutput) { @@ -728,6 +731,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, bool const linkOk = program.link(msg); if (!ok || !linkOk) { slog.e << spirvShader.getInfoLog() << io::endl; + return false; } else { SpvOptions options; options.generateDebugInfo = mGenerateDebugInfo; @@ -749,7 +753,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, } if (internalConfig.wgslOutput) { if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) { - return; + return false; } } @@ -757,6 +761,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader, if (internalConfig.glslOutput) { *internalConfig.glslOutput = glsl; } + return true; } bool GLSLPostProcessor::fullOptimization(const TShader& tShader, diff --git a/libs/filamat/src/GLSLPostProcessor.h b/libs/filamat/src/GLSLPostProcessor.h index 70051d21a6..e7a6363e82 100644 --- a/libs/filamat/src/GLSLPostProcessor.h +++ b/libs/filamat/src/GLSLPostProcessor.h @@ -107,7 +107,7 @@ private: bool fullOptimization(const glslang::TShader& tShader, GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const; - void preprocessOptimization(glslang::TShader& tShader, + bool preprocessOptimization(glslang::TShader& tShader, GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const; /** From 74b09c708a71a934b192fbfd1fd14e032b00f9ae Mon Sep 17 00:00:00 2001 From: bridgewaterrobbie Date: Fri, 28 Feb 2025 13:30:38 -0500 Subject: [PATCH 08/21] Enable TINT_BUILD_SPV_READER on host platform webgpu builds --- libs/filamat/src/GLSLPostProcessor.cpp | 4 ++-- third_party/dawn/tnt/CMakeLists.txt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index 2f6bbea80d..54c8f0645e 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -519,7 +519,7 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl, } bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) { -#ifdef FILAMENT_SUPPORTS_WEBGPU +#if FILAMENT_SUPPORTS_WEBGPU //Currently no options we want to use const tint::spirv::reader::Options readerOpts{}; tint::wgsl::writer::Options writerOpts{}; @@ -547,7 +547,7 @@ bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) *outWsl = wgslOut->wgsl; return true; #else - slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU" << io::endl; + slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU and FILAMENT_SUPPORTS_WEBGPU" << io::endl; return false; #endif diff --git a/third_party/dawn/tnt/CMakeLists.txt b/third_party/dawn/tnt/CMakeLists.txt index 71c3bc1e49..5475c790b2 100644 --- a/third_party/dawn/tnt/CMakeLists.txt +++ b/third_party/dawn/tnt/CMakeLists.txt @@ -12,5 +12,7 @@ set(DAWN_ABSEIL_DIR ${EXTERNAL}/abseil) set(DAWN_SPIRV_TOOLS_DIR ${EXTERNAL}/spirv-tools/) set(DAWN_SPIRV_HEADERS_DIR ${EXTERNAL}/spirv-headers) set(DAWN_GLSLANG_DIR ${EXTERNAL}/glslang/) - +if(IS_HOST_PLATFORM) + set(TINT_BUILD_SPV_READER ON) +endif () add_subdirectory(../ ${PROJECT_BINARY_DIR}/third_party/dawn) \ No newline at end of file From c24535a6e4dcfbb2b24fd80ab78a492c4f6e9d92 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 6 Mar 2025 15:00:48 -0800 Subject: [PATCH 09/21] Update permissions for GitHub release job --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bb9d0394e6..cf2048a9b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,11 @@ name: Release env: RELEASE_TAG: ${{ github.event.inputs.release_tag }} +# The default GITHUB_TOKEN does not have write permissions, which is needed to upload release +# assets. +permissions: + contents: write + on: workflow_dispatch: inputs: From 0e3ef4bd63a9cdb5ae9de1d9e245ec65966f051e Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Thu, 6 Mar 2025 16:05:36 -0800 Subject: [PATCH 10/21] Disable picking for multiview rendering (#8502) Picking is not designed to work with multiview rendering. Disable it when multiview is enabled. --- filament/src/details/Renderer.cpp | 3 +++ filament/src/details/View.cpp | 16 ++++++++++------ filament/src/details/View.h | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index e9963a17a3..13d3138bf9 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -638,6 +638,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { if (isRenderingMultiview) { hasPostProcess = false; msaaOptions.enabled = false; + + // Picking is not supported for multiview rendering. Clear any pending picking queries. + view.clearPickingQueries(); } const uint8_t msaaSampleCount = msaaOptions.enabled ? msaaOptions.sampleCount : 1u; diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index c06e1667ef..48644370c9 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -137,12 +137,7 @@ FView::~FView() noexcept = default; void FView::terminate(FEngine& engine) { // Here we would cleanly free resources we've allocated, or we own (currently none). - while (mActivePickingQueriesList) { - FPickingQuery* const pQuery = mActivePickingQueriesList; - mActivePickingQueriesList = pQuery->next; - pQuery->callback(pQuery->result, pQuery); - FPickingQuery::put(pQuery); - } + clearPickingQueries(); DriverApi& driver = engine.getDriverApi(); driver.destroyBufferObject(mLightUbh); @@ -1178,6 +1173,15 @@ void FView::executePickingQueries(DriverApi& driver, } } +void FView::clearPickingQueries() noexcept { + while (mActivePickingQueriesList) { + FPickingQuery* const pQuery = mActivePickingQueriesList; + mActivePickingQueriesList = pQuery->next; + pQuery->callback(pQuery->result, pQuery); + FPickingQuery::put(pQuery); + } +} + void FView::setTemporalAntiAliasingOptions(TemporalAntiAliasingOptions options) noexcept { options.feedback = clamp(options.feedback, 0.0f, 1.0f); options.filterWidth = std::max(0.2f, options.filterWidth); // below 0.2 causes issues diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 054aa8e11c..13bdf9e503 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -463,6 +463,8 @@ public: void executePickingQueries(backend::DriverApi& driver, backend::RenderTargetHandle handle, math::float2 scale) noexcept; + void clearPickingQueries() noexcept; + void setMaterialGlobal(uint32_t index, math::float4 const& value); math::float4 getMaterialGlobal(uint32_t index) const; From d0a00803c14b651c1bcbee78a032bfa3d4f979dd Mon Sep 17 00:00:00 2001 From: bridgewaterrobbie Date: Thu, 6 Mar 2025 19:28:36 -0500 Subject: [PATCH 11/21] Restore workaround for CONFIG_MAX_INSTANCES and CONFIG_FROXEL_BUFFER_HEIGHT not being a spec constant, because WGSL does not support that being an array length (#8479) --- libs/filamat/src/shaders/CodeGenerator.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index 1fd2d4ab31..37e14a77f7 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -297,12 +297,22 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL", +ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL, 1); - generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES", - +ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES); + if (mTargetApi == TargetApi::WEBGPU) { + // Note: This is a revived hack for a hack. + // + // WGSL doesn't support specialization constants as an array length + // CONFIG_MAX_INSTANCES is only needed for WebGL, so we can replace it with a constant. + // More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005 + out << "const int CONFIG_MAX_INSTANCES = " << (int)CONFIG_MAX_INSTANCES << ";\n"; + out << "const int CONFIG_FROXEL_BUFFER_HEIGHT = 2048;\n"; + } else { + generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES", + +ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES); - // the default of 1024 (16KiB) is needed for 32% of Android devices - generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT", - +ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024); + // the default of 1024 (16KiB) is needed for 32% of Android devices + generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT", + +ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024); + } // directional shadowmap visualization generateSpecializationConstant(out, "CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP", From 719996124899a7dc62e3d5db4210925d0d6ca430 Mon Sep 17 00:00:00 2001 From: Ajmal Kunnummal Date: Thu, 6 Mar 2025 17:05:44 -0800 Subject: [PATCH 12/21] Update the associated uniforms every frame for materials with attached Streams (#8493) BUGS=[399959254] --- .../backend/BufferObjectStreamDescriptor.h | 58 +++++++++++++++++++ .../include/private/backend/CommandStream.h | 1 + .../backend/include/private/backend/Driver.h | 1 + .../include/private/backend/DriverAPI.inc | 4 ++ filament/backend/src/metal/MetalDriver.mm | 4 ++ filament/backend/src/noop/NoopDriver.cpp | 2 + filament/backend/src/opengl/OpenGLDriver.cpp | 46 +++++++++++++++ filament/backend/src/opengl/OpenGLDriver.h | 4 ++ filament/backend/src/vulkan/VulkanDriver.cpp | 4 ++ filament/src/details/Engine.cpp | 3 +- filament/src/details/MaterialInstance.cpp | 21 ++++++- filament/src/details/MaterialInstance.h | 3 + 12 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 filament/backend/include/backend/BufferObjectStreamDescriptor.h diff --git a/filament/backend/include/backend/BufferObjectStreamDescriptor.h b/filament/backend/include/backend/BufferObjectStreamDescriptor.h new file mode 100644 index 0000000000..0a6ae90276 --- /dev/null +++ b/filament/backend/include/backend/BufferObjectStreamDescriptor.h @@ -0,0 +1,58 @@ +/* + * 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_BUFFEROBJECTSTREAMDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_BUFFEROBJECTSTREAMDESCRIPTOR_H + +#include + +#include + +namespace filament::backend { + +/** + * The type of association between a buffer object and a stream. + */ + enum class BufferObjectStreamAssociationType { TRANSFORM_MATRIX }; + +/** + * A descriptor for a buffer object to stream association. + */ +class UTILS_PUBLIC BufferObjectStreamDescriptor { +public: + //! creates an empty descriptor + BufferObjectStreamDescriptor() noexcept = default; + + BufferObjectStreamDescriptor(const BufferObjectStreamDescriptor& rhs) = delete; + BufferObjectStreamDescriptor& operator=(const BufferObjectStreamDescriptor& rhs) = delete; + + BufferObjectStreamDescriptor(BufferObjectStreamDescriptor&& rhs) = default; + BufferObjectStreamDescriptor& operator=(BufferObjectStreamDescriptor&& rhs) = default; + + // -------------------------------------------------------------------------------------------- + + struct StreamDataDescriptor { + uint32_t offset; + Handle stream; + BufferObjectStreamAssociationType associationType; + }; + + std::vector mStreams; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_BUFFEROBJECTSTREAMDESCRIPTOR_H diff --git a/filament/backend/include/private/backend/CommandStream.h b/filament/backend/include/private/backend/CommandStream.h index f722794b52..f2dfe812b9 100644 --- a/filament/backend/include/private/backend/CommandStream.h +++ b/filament/backend/include/private/backend/CommandStream.h @@ -22,6 +22,7 @@ #include "private/backend/Driver.h" #include +#include #include #include #include diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index a00d8e13db..632ed04c4c 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -48,6 +48,7 @@ namespace filament::backend { class BufferDescriptor; +class BufferObjectStreamDescriptor; class CallbackHandler; class PixelBufferDescriptor; class Program; diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 2f2921e671..fbeeeb2fee 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -389,6 +389,10 @@ DECL_DRIVER_API_N(updateBufferObject, backend::BufferDescriptor&&, data, uint32_t, byteOffset) +DECL_DRIVER_API_N(registerBufferObjectStreams, + backend::BufferObjectHandle, ibh, + backend::BufferObjectStreamDescriptor&&, streams) + DECL_DRIVER_API_N(updateBufferObjectUnsynchronized, backend::BufferObjectHandle, ibh, backend::BufferDescriptor&&, data, diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 3d021b1c9d..26221cb92e 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1187,6 +1187,10 @@ void MetalDriver::updateIndexBuffer(Handle ibh, BufferDescriptor& scheduleDestroy(std::move(data)); } +void MetalDriver::registerBufferObjectStreams(Handle boh, BufferObjectStreamDescriptor&& streams) { + // Noop +} + void MetalDriver::updateBufferObject(Handle boh, BufferDescriptor&& data, uint32_t byteOffset) { FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext)) diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index fe37a18bfd..b3fcbb75df 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -250,6 +250,8 @@ void NoopDriver::updateBufferObject(Handle ibh, BufferDescriptor scheduleDestroy(std::move(p)); } +void NoopDriver::registerBufferObjectStreams(Handle boh, BufferObjectStreamDescriptor&& streams) { } + void NoopDriver::updateBufferObjectUnsynchronized(Handle ibh, BufferDescriptor&& p, uint32_t byteOffset) { scheduleDestroy(std::move(p)); diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 6f79963cac..40f291a687 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "private/backend/CommandStream.h" #include "private/backend/Dispatcher.h" @@ -2551,6 +2552,38 @@ void OpenGLDriver::updateIndexBuffer( CHECK_GL_ERROR(utils::slog.e) } +void OpenGLDriver::registerBufferObjectStreams(Handle boh, BufferObjectStreamDescriptor&& streams) { + DEBUG_MARKER() + + GLBufferObject* bo = handle_cast(boh); + mStreamUniformDescriptors[bo->gl.id] = std::move(streams); +} + + +// specialization for mat3f (which has a different alignment, see std140 layout rules) +static void copyMat3f(void* addr, size_t const offset, const mat3f& v) noexcept { + struct mat43 { + float v[3][4]; + }; + + addr = static_cast(addr) + offset; + mat43& temp = *static_cast(addr); + + temp.v[0][0] = v[0][0]; + temp.v[0][1] = v[0][1]; + temp.v[0][2] = v[0][2]; + + temp.v[1][0] = v[1][0]; + temp.v[1][1] = v[1][1]; + temp.v[1][2] = v[1][2]; + + temp.v[2][0] = v[2][0]; + temp.v[2][1] = v[2][1]; + temp.v[2][2] = v[2][2]; + + // don't store anything in temp.v[][3] because there could be uniforms packed there +} + void OpenGLDriver::updateBufferObject( Handle boh, BufferDescriptor&& bd, uint32_t byteOffset) { DEBUG_MARKER() @@ -2564,6 +2597,19 @@ void OpenGLDriver::updateBufferObject( gl.bindVertexArray(nullptr); } + if (UTILS_UNLIKELY(!mStreamUniformDescriptors.empty())) { + auto streamDescriptors = mStreamUniformDescriptors.find(bo->gl.id); + if (streamDescriptors != mStreamUniformDescriptors.end()) { + for (auto const& [offset, stream, associationType] : streamDescriptors->second.mStreams) { + if (associationType == BufferObjectStreamAssociationType::TRANSFORM_MATRIX) { + auto transform = getStreamTransformMatrix(stream); + copyMat3f(bd.buffer, offset, transform); + } + } + mStreamUniformDescriptors.erase(streamDescriptors); + } + } + if (UTILS_UNLIKELY(bo->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) { assert_invariant(bo->gl.buffer); memcpy(static_cast(bo->gl.buffer) + byteOffset, bd.buffer, bd.size); diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 8cb735fac4..6691bd9a97 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "private/backend/Driver.h" #include "private/backend/HandleAllocator.h" @@ -58,6 +59,7 @@ #include #include #include +#include #include #include @@ -364,6 +366,8 @@ private: // the must be accessed from the user thread only std::vector mStreamsWithPendingAcquiredImage; + std::unordered_map mStreamUniformDescriptors; + void attachStream(GLTexture* t, GLStream* stream) noexcept; void detachStream(GLTexture* t) noexcept; void replaceStream(GLTexture* t, GLStream* stream) noexcept; diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 4a89428849..a281382e36 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1148,6 +1148,10 @@ void VulkanDriver::updateIndexBuffer(Handle ibh, BufferDescriptor scheduleDestroy(std::move(p)); } +void VulkanDriver::registerBufferObjectStreams(Handle boh, BufferObjectStreamDescriptor&& streams) { + // Noop +} + void VulkanDriver::updateBufferObject(Handle boh, BufferDescriptor&& bd, uint32_t byteOffset) { VulkanCommandBuffer& commands = mCommands.get(); diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 092df5cb07..01cc8ec9be 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -652,7 +652,8 @@ void FEngine::prepare() { DriverApi& driver = getDriverApi(); for (auto& materialInstanceList: mMaterialInstances) { - materialInstanceList.second.forEach([&driver](FMaterialInstance const* item) { + materialInstanceList.second.forEach([&driver](FMaterialInstance* item) { + item->commitStreamUniformAssociations(driver); item->commit(driver); }); } diff --git a/filament/src/details/MaterialInstance.cpp b/filament/src/details/MaterialInstance.cpp index 075547178e..a9b458ad0a 100644 --- a/filament/src/details/MaterialInstance.cpp +++ b/filament/src/details/MaterialInstance.cpp @@ -24,6 +24,7 @@ #include "details/Material.h" #include "details/MaterialInstance.h" #include "details/Texture.h" +#include "details/Stream.h" #include "private/filament/EngineEnums.h" @@ -190,9 +191,27 @@ void FMaterialInstance::terminate(FEngine& engine) { driver.destroyBufferObject(mUbHandle); } +void FMaterialInstance::commitStreamUniformAssociations(FEngine::DriverApi& driver) { + mHasStreamUniformAssociations = false; + if (!mTextureParameters.empty()) { + backend::BufferObjectStreamDescriptor descriptor; + for (auto const& [binding, p]: mTextureParameters) { + ssize_t offset = mMaterial->getUniformInterfaceBlock().getTransformFieldOffset(binding); + if (offset >= 0) { + mHasStreamUniformAssociations = true; + auto stream = p.texture->getStream()->getHandle(); + descriptor.mStreams.push_back({uint32_t(offset), stream, BufferObjectStreamAssociationType::TRANSFORM_MATRIX}); + } + } + if (descriptor.mStreams.size() > 0) { + driver.registerBufferObjectStreams(mUbHandle, std::move(descriptor)); + } + } +} + void FMaterialInstance::commit(DriverApi& driver) const { // update uniforms if needed - if (mUniforms.isDirty()) { + if (mUniforms.isDirty() || mHasStreamUniformAssociations) { driver.updateBufferObject(mUbHandle, mUniforms.toBufferDescriptor(driver), 0); } if (!mTextureParameters.empty()) { diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index 741b911b7a..f5efa27c78 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -65,6 +65,8 @@ public: void terminate(FEngine& engine); + void commitStreamUniformAssociations(FEngine::DriverApi& driver); + void commit(FEngine::DriverApi& driver) const; void use(FEngine::DriverApi& driver) const; @@ -272,6 +274,7 @@ private: tsl::robin_map mTextureParameters; mutable DescriptorSet mDescriptorSet; UniformBuffer mUniforms; + bool mHasStreamUniformAssociations = false; backend::PolygonOffset mPolygonOffset{}; backend::StencilState mStencilState{}; From 5091b3112da71df7a6d138d7d8bceb58e7be6d31 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Fri, 7 Mar 2025 09:46:04 -0800 Subject: [PATCH 13/21] matdbg: fix variant issue for surface materials (#8503) - The set of active variants were not set correctly for surface materials since the frag/vert pairs could have different variant. - Fix the default selection logic in the UI - Random clean-ups FIXES=328699979 --- filament/src/details/Material.h | 9 ++++++++- libs/matdbg/src/ApiHandler.cpp | 2 +- libs/matdbg/src/ShaderInfo.cpp | 13 +++++++++++++ libs/matdbg/web/api.js | 8 ++++---- libs/matdbg/web/app.js | 29 +++++++++-------------------- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index d0e9d1492b..d6cca777be 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -154,7 +154,14 @@ public: #if FILAMENT_ENABLE_MATDBG assert_invariant((size_t)variant.key < VARIANT_COUNT); std::unique_lock lock(mActiveProgramsLock); - mActivePrograms.set(variant.key); + if (getMaterialDomain() == MaterialDomain::SURFACE) { + auto vert = Variant::filterVariantVertex(variant); + auto frag = Variant::filterVariantFragment(variant); + mActivePrograms.set(vert.key); + mActivePrograms.set(frag.key); + } else { + mActivePrograms.set(variant.key); + } lock.unlock(); if (isSharedVariant(variant)) { diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index 80d00e2338..3c53265317 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -336,7 +336,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return error(__LINE__, uri); } bool const last = (++index) == mServer->mMaterialRecords.size(); - mg_printf(conn, "\"%8.8x\": %s %s", pair.first, writer.getJsonString(), + mg_printf(conn, "\"%8.8x\": %s%s", pair.first, writer.getJsonString(), last ? "" : ","); } mg_printf(conn, "}"); diff --git a/libs/matdbg/src/ShaderInfo.cpp b/libs/matdbg/src/ShaderInfo.cpp index cba7bf648d..632c20d711 100644 --- a/libs/matdbg/src/ShaderInfo.cpp +++ b/libs/matdbg/src/ShaderInfo.cpp @@ -16,6 +16,8 @@ #include +#include "CommonWriter.h" + #include #include #include @@ -54,6 +56,11 @@ bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType return true; } + MaterialDomain domain; + if (!read(container, ChunkType::MaterialDomain, reinterpret_cast(&domain))) { + return false; + } + auto [start, end] = container.getChunkRange(chunkType); Unflattener unflattener(start, end); @@ -84,6 +91,12 @@ bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType return false; } + auto stage = ShaderStage(pipelineStageValue); + if (domain == MaterialDomain::SURFACE) { + variant = stage == ShaderStage::VERTEX ? + Variant::filterVariantVertex(variant) : + Variant::filterVariantFragment(variant); + } *info++ = { .shaderModel = ShaderModel(shaderModelValue), .variant = variant, diff --git a/libs/matdbg/web/api.js b/libs/matdbg/web/api.js index f16fec3a90..a6e62f788d 100644 --- a/libs/matdbg/web/api.js +++ b/libs/matdbg/web/api.js @@ -68,11 +68,11 @@ async function fetchMatIds() { } async function queryActiveShaders() { - const activeMaterials = await _fetchJson("api/active"); + const activeVariants = await _fetchJson("api/active"); const actives = {}; - for (matid in activeMaterials) { - const backend = activeMaterials[matid][0]; - const variants = activeMaterials[matid].slice(1); + for (matid in activeVariants) { + const backend = activeVariants[matid][0]; + const variants = activeVariants[matid].slice(1); actives[matid] = { backend, variants }; diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index 58858daa3c..e9bad73a01 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -702,29 +702,19 @@ class MaterialSidePanel extends LitElement { updated(props) { if (props.has('database')) { - const items = []; - // Names need not be unique, so we display a numeric suffix for non-unique names. // To achieve stable ordering of anonymous materials, we first sort by matid. - const labels = new Set(); const matids = Object.keys(this.database).sort(); - const duplicatedLabels = {}; - for (const matid of matids) { - const name = this.database[matid].name || kUntitledPlaceholder; - if (labels.has(name)) { - duplicatedLabels[name] = 0; - } else { - labels.add(name); - } - } + const names = matids.map(matid => (this.database[matid].name || kUntitledPlaceholder)); + const labelCount = {}; + names.forEach(name => labelCount[name] = (labelCount[name] || 0) + 1); + const duplicates = names.filter(name => labelCount[name] > 1); this.materials = matids.map((matid) => { const material = this.database[matid]; let name = material.name || kUntitledPlaceholder; - if (name in duplicatedLabels) { - const index = duplicatedLabels[name]; - duplicatedLabels[name] = index + 1; - name = `${name} (${index})`; + if (duplicates.includes(name)) { + name = `${name} (${labelCount[name]--})`; } return { matid: matid, @@ -938,8 +928,7 @@ class MatdbgViewer extends LitElement { } ); - let materials = await fetchMaterials(); - this.database = materials; + this.database = await fetchMaterials(); // This is the user preferences stored in localStorage let hideInactiveVariantsVal = localStorage.getItem('option-hide-inactive-variants'); @@ -1070,8 +1059,8 @@ class MatdbgViewer extends LitElement { const activeVariants = this.activeShaders[this.currentMaterial].variants; const materialShaders = material[this.currentBackend]; for (let shader in materialShaders) { - let ind = activeVariants.indexOf(+shader); - if (ind >= 0) { + const shaderVariant = materialShaders[shader].variant; + if (activeVariants.indexOf(shaderVariant) >= 0) { this.currentShaderIndex = +shader; break; } From 2f4e48b6b938da3a52cb37599627abfbb2a8dcbc Mon Sep 17 00:00:00 2001 From: Konstantin Sakhin Date: Fri, 7 Mar 2025 14:11:04 -0600 Subject: [PATCH 14/21] Texture: prevent SIGILL in sampler validator. (#8468) Co-authored-by: Romain Guy --- filament/src/details/Texture.cpp | 38 +++++++++++++++++--------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index d018f3800f..3749344d35 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -164,6 +164,26 @@ Texture* Texture::Builder::build(Engine& engine) { (isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory) << "Texture is PROTECTED but protected textures are not supported"; + const auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool { + switch (sampler) { + case SamplerType::SAMPLER_2D: + case SamplerType::SAMPLER_CUBEMAP: + case SamplerType::SAMPLER_EXTERNAL: + return true; + case SamplerType::SAMPLER_3D: + case SamplerType::SAMPLER_2D_ARRAY: + return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1); + case SamplerType::SAMPLER_CUBEMAP_ARRAY: + return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2); + } + return false; + }; + + // Validate sampler before any further interaction with it. + FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget)) + << "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level " + << uint8_t(engine.getActiveFeatureLevel()); + // SAMPLER_EXTERNAL implies imported. if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) { mImpl->mExternal = true; @@ -216,24 +236,6 @@ Texture* Texture::Builder::build(Engine& engine) { FILAMENT_CHECK_PRECONDITION(!swizzled) << "WebGL does not support texture swizzling."; #endif - auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool { - switch (sampler) { - case SamplerType::SAMPLER_2D: - case SamplerType::SAMPLER_CUBEMAP: - case SamplerType::SAMPLER_EXTERNAL: - return true; - case SamplerType::SAMPLER_3D: - case SamplerType::SAMPLER_2D_ARRAY: - return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1); - case SamplerType::SAMPLER_CUBEMAP_ARRAY: - return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2); - } - }; - - FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget)) - << "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level " - << uint8_t(engine.getActiveFeatureLevel()); - FILAMENT_CHECK_PRECONDITION((swizzled && sampleable) || !swizzled) << "Swizzled texture must be SAMPLEABLE"; From ee68872a473989706ba1382aa67a318fb088e72f Mon Sep 17 00:00:00 2001 From: alizahlalani <39961857+alizahlalani@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:28:56 -0500 Subject: [PATCH 15/21] Add ahb mapping util functions to map ahb usage and format to TextureUsage and TextureFormat (#8491) --- filament/backend/CMakeLists.txt | 4 + .../backend/include/backend/DriverEnums.h | 27 +++++ .../private/backend/BackendUtilsAndroid.h | 36 +++++++ filament/backend/src/BackendUtilsAndroid.cpp | 98 +++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 filament/backend/include/private/backend/BackendUtilsAndroid.h create mode 100644 filament/backend/src/BackendUtilsAndroid.cpp diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index e4cc81a472..b987e18ecb 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -246,6 +246,10 @@ if (FILAMENT_SUPPORTS_WEBGPU) ) endif() +if (ANDROID) + list(APPEND SRCS src/BackendUtilsAndroid.cpp) +endif() + # ================================================================================================== # Definitions # ================================================================================================== diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 551a7f19ad..f0561be709 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -807,6 +807,33 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept { } } +inline constexpr bool isColorFormat(TextureFormat format) noexcept { + switch (format) { + // Standard color formats + case TextureFormat::R8: + case TextureFormat::RG8: + case TextureFormat::RGBA8: + case TextureFormat::R16F: + case TextureFormat::RG16F: + case TextureFormat::RGBA16F: + case TextureFormat::R32F: + case TextureFormat::RG32F: + case TextureFormat::RGBA32F: + case TextureFormat::RGB10_A2: + case TextureFormat::R11F_G11F_B10F: + case TextureFormat::SRGB8: + case TextureFormat::SRGB8_A8: + case TextureFormat::RGB8: + case TextureFormat::RGB565: + case TextureFormat::RGB5_A1: + case TextureFormat::RGBA4: + return true; + default: + break; + } + return false; +} + static constexpr bool isUnsignedIntFormat(TextureFormat format) { switch (format) { case TextureFormat::R8UI: diff --git a/filament/backend/include/private/backend/BackendUtilsAndroid.h b/filament/backend/include/private/backend/BackendUtilsAndroid.h new file mode 100644 index 0000000000..21ad61f48a --- /dev/null +++ b/filament/backend/include/private/backend/BackendUtilsAndroid.h @@ -0,0 +1,36 @@ +/* + * 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_PRIVATE_BACKENDUTILSANDROID_H +#define TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H + +#include + +namespace filament::backend { + +/** + * Maps AHardwareBuffer format to TextureFormat. + */ +TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept; + +/** + * Maps AHardwareBuffer usage to TextureUsage. + */ +TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept; + +} // namespace filament + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H diff --git a/filament/backend/src/BackendUtilsAndroid.cpp b/filament/backend/src/BackendUtilsAndroid.cpp new file mode 100644 index 0000000000..3eb967650b --- /dev/null +++ b/filament/backend/src/BackendUtilsAndroid.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "private/backend/BackendUtilsAndroid.h" + +#include + +namespace filament::backend { + +TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept { + if (isSrgbTransfer) { + switch (format) { + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + return TextureFormat::SRGB8; + default: + return TextureFormat::SRGB8_A8; + } + } + switch (format) { + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: + return TextureFormat::RGBA8; + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: + return TextureFormat::RGB8; + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: + return TextureFormat::RGB565; + case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: + return TextureFormat::RGBA16F; + case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: + return TextureFormat::RGB10_A2; + case AHARDWAREBUFFER_FORMAT_D16_UNORM: + return TextureFormat::DEPTH16; + case AHARDWAREBUFFER_FORMAT_D24_UNORM: + return TextureFormat::DEPTH24; + case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: + return TextureFormat::DEPTH24_STENCIL8; + case AHARDWAREBUFFER_FORMAT_D32_FLOAT: + return TextureFormat::DEPTH32F; + case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: + return TextureFormat::DEPTH32F_STENCIL8; + case AHARDWAREBUFFER_FORMAT_S8_UINT: + return TextureFormat::STENCIL8; + case AHARDWAREBUFFER_FORMAT_R8_UNORM: + return TextureFormat::R8; + default: + return TextureFormat::UNUSED; + } +} + +TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept { + TextureUsage usageFlags = TextureUsage::NONE; + + if (usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) { + usageFlags |= TextureUsage::SAMPLEABLE; + } + + if (usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) { + if (isDepthFormat(format)) { + usageFlags |= TextureUsage::DEPTH_ATTACHMENT; + } + if (isStencilFormat(format)) { + usageFlags |= TextureUsage::STENCIL_ATTACHMENT; + } + if (isColorFormat(format)) { + usageFlags |= TextureUsage::COLOR_ATTACHMENT; + } + } + + if (usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) { + usageFlags |= TextureUsage::UPLOADABLE; + } + + if (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) { + usageFlags |= TextureUsage::PROTECTED; + } + + if (usageFlags == TextureUsage::NONE) { + usageFlags = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE; + } + + return usageFlags; +} + +} // namespace backend::filament From e825f439358d2c33ac7054bc5fa54afa816f0e2c Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Fri, 7 Mar 2025 15:54:22 -0800 Subject: [PATCH 16/21] matdbg: indicate shader model (#8504) Shader model (desktop or mobile) wasn't really accounted for in the UI. This means that we will get shaders that look like duplicates (same variant). In this work, we pass the current shader model from engine into the frontend and filter out variants of a different shader model. Moreover, for matinfo, we use a specific dbg shader model (matinfo) to indicate it is in that mode. We add UI in matinfo to show the shadermodel. So UI updates as well. --- filament/src/details/Engine.cpp | 3 +- libs/matdbg/include/matdbg/DebugServer.h | 18 ++++- libs/matdbg/include/matdbg/JsonWriter.h | 5 +- libs/matdbg/src/ApiHandler.cpp | 37 +++++----- libs/matdbg/src/DebugServer.cpp | 7 +- libs/matdbg/src/JsonWriter.cpp | 15 +++- libs/matdbg/src/ShaderInfo.cpp | 1 - libs/matdbg/web/api.js | 7 +- libs/matdbg/web/app.js | 90 ++++++++++++++++-------- tools/matinfo/src/main.cpp | 2 +- 10 files changed, 123 insertions(+), 62 deletions(-) diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 01cc8ec9be..741e2b3b62 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -751,7 +751,8 @@ int FEngine::loop() { #endif if (portString != nullptr) { const int port = atoi(portString); - debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), port); + debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), + matdbg::DbgShaderModel((uint8_t) mDriver->getShaderModel()), port); // Sometimes the server can fail to spin up (e.g. if the above port is already in use). // When this occurs, carry onward, developers can look at civetweb.txt for details. diff --git a/libs/matdbg/include/matdbg/DebugServer.h b/libs/matdbg/include/matdbg/DebugServer.h index 86aaa79bd1..272d68ab28 100644 --- a/libs/matdbg/include/matdbg/DebugServer.h +++ b/libs/matdbg/include/matdbg/DebugServer.h @@ -41,6 +41,13 @@ struct MaterialRecord { VariantList activeVariants; }; +// Matches DriverEnums' ShaderModel +enum class DbgShaderModel { + MOBILE = 1, //!< Mobile level functionality + DESKTOP = 2, //!< Desktop level functionality + MATINFO = 10, //!< To indicate debug server is running from matinfo +}; + /** * Server-side material debugger. * @@ -52,7 +59,8 @@ public: static std::string_view const kSuccessHeader; static std::string_view const kErrorHeader; - DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port); + DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, + DbgShaderModel perferredShaderModel, int port); ~DebugServer(); /** @@ -85,10 +93,13 @@ public: bool isReady() const { return mServer; } private: + // called from ApiHandler MaterialRecord const* getRecord(const MaterialKey& key) const; + // called from ApiHandler void updateActiveVariants(); + // called from ApiHandler /** * Replaces the entire content of a particular shader variant. The given shader index uses the * same ordering that the variants have within the package. @@ -96,8 +107,9 @@ private: bool handleEditCommand(const MaterialKey& mat, backend::Backend api, int shaderIndex, const char* newShaderContent, size_t newShaderLength); - const backend::Backend mBackend; - const backend::ShaderLanguage mShaderLanguage; + backend::Backend const mBackend; + backend::ShaderLanguage const mShaderLanguage; + DbgShaderModel const mPreferredShaderModel; CivetServer* mServer; diff --git a/libs/matdbg/include/matdbg/JsonWriter.h b/libs/matdbg/include/matdbg/JsonWriter.h index 4291f6f749..f1ff7f7aae 100644 --- a/libs/matdbg/include/matdbg/JsonWriter.h +++ b/libs/matdbg/include/matdbg/JsonWriter.h @@ -17,6 +17,8 @@ #ifndef MATDBG_JSONWRITER_H #define MATDBG_JSONWRITER_H +#include + #include #include @@ -47,7 +49,8 @@ public: // shader index is an active variant. Each bit in the activeVariants bitmask // represents one of the possible variant combinations. bool writeActiveInfo(const filaflat::ChunkContainer& package, - backend::ShaderLanguage shaderLanguage, VariantList activeVariants); + backend::ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, + VariantList activeVariants); private: utils::CString mJsonString; diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index 3c53265317..fb3c0673aa 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -332,7 +332,8 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return error(__LINE__, uri); } JsonWriter writer; - if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) { + if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, + mServer->mPreferredShaderModel, record.activeVariants)) { return error(__LINE__, uri); } bool const last = (++index) == mServer->mMaterialRecords.size(); @@ -356,6 +357,18 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return true; } + auto writeMaterialRecord = [&](JsonWriter* writer, MaterialRecord const* record) { + ChunkContainer package(record->package, record->packageSize); + if (!package.parse()) { + return error(__LINE__, uri); + } + + if (!writer->writeMaterialInfo(package)) { + return error(__LINE__, uri); + } + return true; + }; + if (uri == "/api/materials") { std::unique_lock const lock(mServer->mMaterialRecordsMutex); mg_printf(conn, kSuccessHeader.data(), "application/json"); @@ -363,17 +376,11 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { int index = 0; for (auto const& record: mServer->mMaterialRecords) { bool const last = (++index) == mServer->mMaterialRecords.size(); - - ChunkContainer package(record.second.package, record.second.packageSize); - if (!package.parse()) { - return error(__LINE__, uri); - } - + auto const& mat = record.second; JsonWriter writer; - if (!writer.writeMaterialInfo(package)) { - return error(__LINE__, uri); + if (!writeMaterialRecord(&writer, &mat)) { + return false; } - mg_printf(conn, "{ \"matid\": \"%8.8x\", %s } %s", record.first, writer.getJsonString(), last ? "" : ","); } @@ -386,15 +393,9 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { if (!result) { return error(__LINE__, uri); } - - ChunkContainer package(result->package, result->packageSize); - if (!package.parse()) { - return error(__LINE__, uri); - } - JsonWriter writer; - if (!writer.writeMaterialInfo(package)) { - return error(__LINE__, uri); + if (!writeMaterialRecord(&writer, result)) { + return false; } mg_printf(conn, kSuccessHeader.data(), "application/json"); mg_printf(conn, "{ %s }", writer.getJsonString()); diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index d75952728b..9285bc38c5 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -122,8 +122,11 @@ private: DebugServer* mServer; }; -DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port) - : mBackend(backend), mShaderLanguage(shaderLanguage) { +DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, + DbgShaderModel perferredShaderModel, int port) + : mBackend(backend), + mShaderLanguage(shaderLanguage), + mPreferredShaderModel(perferredShaderModel) { #if !SERVE_FROM_SOURCE_TREE ASSET_MAP["/index.html"] = { diff --git a/libs/matdbg/src/JsonWriter.cpp b/libs/matdbg/src/JsonWriter.cpp index 2a22eaeae2..7a5409927b 100644 --- a/libs/matdbg/src/JsonWriter.cpp +++ b/libs/matdbg/src/JsonWriter.cpp @@ -232,7 +232,7 @@ size_t JsonWriter::getJsonSize() const { } bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, - ShaderLanguage shaderLanguage, VariantList activeVariants) { + ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, VariantList activeVariants) { vector shaders; ostringstream json; json << "[\""; @@ -260,7 +260,20 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, shaders.resize(getShaderCount(package, chunkType)); getShaderInfo(package, shaders.data(), chunkType); + json << "\", \""; + switch (shaderModel) { + case DbgShaderModel::DESKTOP: + json << toString(ShaderModel::DESKTOP); + break; + case DbgShaderModel::MOBILE: + json << toString(ShaderModel::MOBILE); + break; + case DbgShaderModel::MATINFO: + json << "matinfo"; + break; + } json << "\""; + for (size_t variant = 0; variant < activeVariants.size(); variant++) { if (activeVariants[variant]) { json << ", " << variant; diff --git a/libs/matdbg/src/ShaderInfo.cpp b/libs/matdbg/src/ShaderInfo.cpp index 632c20d711..320e1b383a 100644 --- a/libs/matdbg/src/ShaderInfo.cpp +++ b/libs/matdbg/src/ShaderInfo.cpp @@ -50,7 +50,6 @@ size_t getShaderCount(const ChunkContainer& container, ChunkType type) { return shaderCount; } - bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType chunkType) { if (!container.hasChunk(chunkType)) { return true; diff --git a/libs/matdbg/web/api.js b/libs/matdbg/web/api.js index a6e62f788d..79eedf78bc 100644 --- a/libs/matdbg/web/api.js +++ b/libs/matdbg/web/api.js @@ -72,10 +72,9 @@ async function queryActiveShaders() { const actives = {}; for (matid in activeVariants) { const backend = activeVariants[matid][0]; - const variants = activeVariants[matid].slice(1); - actives[matid] = { - backend, variants - }; + const shaderModel = activeVariants[matid][1]; + const variants = activeVariants[matid].slice(2); + actives[matid] = { backend, shaderModel, variants }; } return actives; } diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index e9bad73a01..56a85d7230 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -59,8 +59,8 @@ const FOREGROUND_COLOR = '#fafafa'; const INACTIVE_COLOR = '#9a9a9a'; const DARKER_INACTIVE_COLOR = '#6f6f6f'; const LIGHTER_INACTIVE_COLOR = '#d9d9d9'; -const UNSELECTED_COLOR = '#dfdfdf'; -const BACKGROUND_COLOR = '#5362e5'; +const UNSELECTED_COLOR = '#d0d0d0'; +const BACKGROUND_COLOR = '#6885c5'; const HOVER_BACKGROUND_COLOR = '#b3c2ff'; const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60; const REGULAR_FONT_SIZE = 12; @@ -343,7 +343,7 @@ class MenuSection extends LitElement { color: ${unsafeCSS(UNSELECTED_COLOR)}; } .section-title { - font-size: 16px; + font-size: 20px; color: ${unsafeCSS(UNSELECTED_COLOR)}; cursor: pointer; } @@ -365,6 +365,9 @@ class MenuSection extends LitElement { align-items: center; justify-content: space-between; } + .expanded-title { + color: ${unsafeCSS(FOREGROUND_COLOR)}; + } `; } @@ -380,9 +383,10 @@ class MenuSection extends LitElement { render() { const expandedIcon = this.showing ? '-' : '+'; const slot = (() => html``)(); + const epandedTitleClass = this.showing ? 'expanded-title' : ''; return html`
-
+
${this.title} ${expandedIcon}

@@ -460,6 +464,7 @@ class AdvancedOptions extends LitElement { static get properties() { return { currentBackend: {type: String, attribute: 'current-backend'}, + currentShaderModel: {type: String, attribute: 'current-shader-model'}, hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'}, availableBackends: {type: Array, state: true}, }; @@ -478,6 +483,7 @@ class AdvancedOptions extends LitElement { flex-direction: column; justify-content: center; align-items: flex-start; + margin-bottom: 6px; } .borderless { border: 1px solid rgba(0,0,0,0); @@ -570,7 +576,7 @@ class AdvancedOptions extends LitElement { return html`
Current Backend
-
+ ${div}
@@ -578,6 +584,9 @@ class AdvancedOptions extends LitElement { } _hideInactiveVariantsOption() { + if (this.currentShaderModel == 'matinfo') { + return null; + } const onChange = (ev) => { this.dispatchEvent( new CustomEvent( @@ -585,7 +594,7 @@ class AdvancedOptions extends LitElement { {detail: null, bubbles: true, composed: true})); } return html` -
+
${languagesDiv}
`; } - _buildShaderDiv(showAllShaders) { + _buildShaderDiv() { if (!this.variants) { return null; } + const isMatinfo = this.currentShaderModel == 'matinfo'; let variants = this.variants .sort((a, b) => { @@ -798,7 +809,10 @@ class MaterialSidePanel extends LitElement { if (b.active && !a.active) return 1; return 0; }) - .filter((variant) => (!this.hideInactiveVariants || variant.shader.active)) + .filter(variant => (!this.hideInactiveVariants || variant.shader.active)) + .filter(variant => ( + isMatinfo || variant.shader.shaderModel == this.currentShaderModel + )) .map((variant) => { let divClass = 'material_variant_language'; const shaderIndex = +variant.shader.index; @@ -807,7 +821,7 @@ class MaterialSidePanel extends LitElement { if (isVariantSelected) { divClass += ' selected'; } - if (!isActive) { + if (!isActive && !isMatinfo) { divClass += ' inactive'; } const onClickVariant = this._handleVariantClick.bind(this, shaderIndex); @@ -816,11 +830,18 @@ class MaterialSidePanel extends LitElement { if (vstring.length > 0) { vstring = `[${vstring}]`; } + const shaderModelSymbol = { + 'desktop': '🄳 ', + 'mobile': '🄼 ', + }; + let languagesDiv = isVariantSelected ? this._buildLanguagesDiv(isActive) : null; - const stage = (isVariantSelected ? '● ' : '') + variant.shader.pipelineStage; + const stage = + (isMatinfo ? shaderModelSymbol[variant.shader.shaderModel] : '') + + (variant.shader.pipelineStage.indexOf('vertex') >=0 ? '𝕍ert' : '𝔽rag'); return html`
-
${stage} ${vstring}
+
${stage}  ${vstring}
${languagesDiv ?? nothing} ` @@ -829,6 +850,7 @@ class MaterialSidePanel extends LitElement { } render() { + const isMatinfo = this.currentShaderModel == 'matinfo'; const sections = (title, domain) => { const mats = this.materials .filter((m) => m.domain == domain) @@ -844,14 +866,12 @@ class MaterialSidePanel extends LitElement { const isMaterialSelected = mat.matid === this.currentMaterial; if (isMaterialSelected) { divClass += ' selected'; - // If we are looking at an inactive material, show all shaders regardless. - const showAllShaders = !material.active; - shaderDiv = this._buildShaderDiv(showAllShaders); + shaderDiv = this._buildShaderDiv(); } - if (!material.active) { + if (!material.active && !isMatinfo) { divClass += " inactive"; } - const matName = (isMaterialSelected ? '● ' : '') + mat.name; + const matName = mat.name; return html`
${matName} @@ -868,6 +888,7 @@ class MaterialSidePanel extends LitElement { (() => html` `)(); @@ -875,7 +896,7 @@ class MaterialSidePanel extends LitElement { return html`
-
matdbg
+
${isMatinfo ? 'matinfo' : 'matdbg'}
${sections("Surface", "surface") ?? nothing} ${sections("Post-processing", "postpro") ?? nothing} @@ -968,6 +989,7 @@ class MatdbgViewer extends LitElement { this.currentMaterial = null; this.currentLanguage = null; this.currentBackend = null; + this.currentShaderModel = null; this.hideInactiveVariants = false; this.init(); @@ -1038,6 +1060,7 @@ class MatdbgViewer extends LitElement { // Each material has a list of variants compiled for it, this index tracks a position in the list. currentShaderIndex: {type: Number, state: true}, currentBackend: {type: String, state: true}, + currentShaderModel: {type: String, state: true}, codeViewerExpectedWidth: {type: Number, state: true}, codeViewerExpectedHeight: {type: Number, state: true}, @@ -1084,7 +1107,6 @@ class MatdbgViewer extends LitElement { shader.modified = false; this.database = this.database; } - // Size of the editor will be adjusted due to the code being loaded, we try to // fit the editor again by calling the resize signal. setTimeout(this._onResize.bind(this), 700); @@ -1108,22 +1130,29 @@ class MatdbgViewer extends LitElement { } } if (_validDict(this.activeShaders)) { - let backends = {}; + let setBackend = null; + let setShaderModel = null; for (let matid in this.activeShaders) { const backend = this.activeShaders[matid].backend; - if (backend in backends) { - backends[backend] = backends[backend] + 1; - } else { - backends[backend] = 1; + if (!setBackend && backend) { + setBackend = backend; + } + const shaderModel = this.activeShaders[matid].shaderModel; + if (!setShaderModel && shaderModel) { + setShaderModel = shaderModel; } } - let backendList = Object.keys(backends); - if (backendList.length > 0) { - this.currentBackend = backendList[0]; + if (this.currentBackend != setBackend) { + this.currentBackend = setBackend; } - } else if (!this.currentBackend) { + if (this.currentShaderModel != setShaderModel) { + this.currentShaderModel = setShaderModel; + } + + } else if (!this.currentBackend || !this.currentShaderModel) { // Make a guess on the backend if one wasn't from activeShaders. this.currentBackend = guessBackend(); + this.currentShaderModel = 'matinfo'; } this._sidepanel.database = this.database; @@ -1155,6 +1184,7 @@ class MatdbgViewer extends LitElement { current-shader-index="${this.currentShaderIndex}" current-material="${this.currentMaterial}" current-backend="${this.currentBackend}" + current-shader-model="${this.currentShaderModel}" ?hide-inactive-variants="${this.hideInactiveVariants}" > Date: Mon, 10 Mar 2025 09:58:58 -0700 Subject: [PATCH 17/21] Add a way to pass a transform matrix along with Stream::setAcquiredImage (#8496) BUGS=[399959254] --------- Co-authored-by: Syed Idris Shah Co-authored-by: Haneul Kim Co-authored-by: Powei Feng Co-authored-by: Doris Wu Co-authored-by: Mathias Agopian --- filament/backend/include/backend/AcquiredImage.h | 1 + filament/backend/include/private/backend/Driver.h | 1 + .../backend/include/private/backend/DriverAPI.inc | 2 +- .../include/private/backend/HandleAllocator.h | 2 +- filament/backend/src/Driver.cpp | 4 ++-- filament/backend/src/metal/MetalDriver.mm | 2 +- filament/backend/src/noop/NoopDriver.cpp | 2 +- filament/backend/src/opengl/OpenGLDriver.cpp | 13 +++++++++---- filament/backend/src/opengl/OpenGLDriver.h | 3 +++ filament/backend/src/vulkan/VulkanDriver.cpp | 2 +- filament/include/filament/Stream.h | 8 ++++++-- filament/src/Stream.cpp | 8 ++++---- filament/src/details/Stream.cpp | 8 ++++---- filament/src/details/Stream.h | 6 ++++-- 14 files changed, 39 insertions(+), 23 deletions(-) diff --git a/filament/backend/include/backend/AcquiredImage.h b/filament/backend/include/backend/AcquiredImage.h index fec27a53fb..ff0840e523 100644 --- a/filament/backend/include/backend/AcquiredImage.h +++ b/filament/backend/include/backend/AcquiredImage.h @@ -18,6 +18,7 @@ #define TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H #include +#include namespace filament::backend { diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index 632ed04c4c..fab522777b 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index fbeeeb2fee..f87d18b4f6 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -339,7 +339,7 @@ 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) DECL_DRIVER_API_SYNCHRONOUS_0(backend::StreamHandle, createStreamAcquired) -DECL_DRIVER_API_SYNCHRONOUS_N(void, setAcquiredImage, backend::StreamHandle, stream, void*, image, backend::CallbackHandler*, handler, backend::StreamCallback, cb, void*, userData) +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) diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index 80c7d5c836..389ff98293 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -40,7 +40,7 @@ #include #include -#define HandleAllocatorGL HandleAllocator<32, 96, 136> // ~4520 / pool / MiB +#define HandleAllocatorGL HandleAllocator<32, 96, 184> // ~4520 / pool / MiB #define HandleAllocatorVK HandleAllocator<64, 160, 312> // ~1820 / pool / MiB #define HandleAllocatorMTL HandleAllocator<32, 64, 552> // ~1660 / pool / MiB diff --git a/filament/backend/src/Driver.cpp b/filament/backend/src/Driver.cpp index f33f855d9f..706ee5de42 100644 --- a/filament/backend/src/Driver.cpp +++ b/filament/backend/src/Driver.cpp @@ -140,8 +140,8 @@ void DriverBase::scheduleDestroySlow(BufferDescriptor&& buffer) noexcept { // This is called from an async driver method so it's in the GL thread, but purge is called // on the user thread. This is typically called 0 or 1 times per frame. void DriverBase::scheduleRelease(AcquiredImage const& image) noexcept { - scheduleCallback(image.handler, [image]() { - image.callback(image.image, image.userData); + scheduleCallback(image.handler, [callback = image.callback, image = image.image, userData = image.userData]() { + callback(image, userData); }); } diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 26221cb92e..b2c9173ce7 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -984,7 +984,7 @@ Handle MetalDriver::createStreamAcquired() { return {}; } -void MetalDriver::setAcquiredImage(Handle sh, void* image, +void MetalDriver::setAcquiredImage(Handle sh, void* image, const math::mat3f& transform, CallbackHandler* handler, StreamCallback cb, void* userData) { } diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index b3fcbb75df..88b42a48a4 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -133,7 +133,7 @@ Handle NoopDriver::createStreamAcquired() { return {}; } -void NoopDriver::setAcquiredImage(Handle sh, void* image, +void NoopDriver::setAcquiredImage(Handle sh, void* image, const math::mat3f& transform, CallbackHandler* handler, StreamCallback cb, void* userData) { } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 40f291a687..326a84b76b 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -2086,7 +2086,7 @@ Handle OpenGLDriver::createStreamAcquired() { // setAcquiredImage should be called by the user outside of beginFrame / endFrame, and should be // called only once per frame. If the user pushes images to the same stream multiple times in a // single frame, we emit a warning and honor only the final image, but still invoke all callbacks. -void OpenGLDriver::setAcquiredImage(Handle sh, void* hwbuffer, +void OpenGLDriver::setAcquiredImage(Handle sh, void* hwbuffer, const math::mat3f& transform, CallbackHandler* handler, StreamCallback cb, void* userData) { GLStream* glstream = handle_cast(sh); assert_invariant(glstream->streamType == StreamType::ACQUIRED); @@ -2122,7 +2122,7 @@ void OpenGLDriver::updateStreams(DriverApi* driver) { // Bind the stashed EGLImage to its corresponding GL texture as soon as we start // making the GL calls for the upcoming frame. - driver->queueCommand([this, s, image = s->user_thread.acquired.image, previousImage]() { + driver->queueCommand([this, s, image = s->user_thread.acquired.image, previousImage, transform = s->user_thread.transform]() { auto& streams = mTexturesWithStreamsAttached; auto pos = std::find_if(streams.begin(), streams.end(), @@ -2137,6 +2137,7 @@ void OpenGLDriver::updateStreams(DriverApi* driver) { t->gl.target = t->externalTexture->target; t->gl.id = t->externalTexture->id; bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); + s->transform = transform; } } @@ -2167,8 +2168,12 @@ int64_t OpenGLDriver::getStreamTimestamp(Handle sh) { math::mat3f OpenGLDriver::getStreamTransformMatrix(Handle sh) { if (sh) { - GLStream* s = handle_cast(sh); - return mPlatform.getTransformMatrix(s->stream); + GLStream* s = handle_cast(sh); + if (s->streamType == StreamType::NATIVE) { + return mPlatform.getTransformMatrix(s->stream); + } else { + return s->transform; + } } return math::mat3f(); } diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 6691bd9a97..ecc1c89a84 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -161,7 +161,10 @@ public: uint8_t cur = 0; AcquiredImage acquired; AcquiredImage pending; + math::mat3f transform; } user_thread; + + math::mat3f transform; }; struct GLRenderTarget : public HwRenderTarget { diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index a281382e36..bd44b8c7f3 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -907,7 +907,7 @@ Handle VulkanDriver::createStreamAcquired() { return {}; } -void VulkanDriver::setAcquiredImage(Handle sh, void* image, +void VulkanDriver::setAcquiredImage(Handle sh, void* image, const math::mat3f& transform, CallbackHandler* handler, StreamCallback cb, void* userData) { } diff --git a/filament/include/filament/Stream.h b/filament/include/filament/Stream.h index f9e5a60e8e..9cf7fa1634 100644 --- a/filament/include/filament/Stream.h +++ b/filament/include/filament/Stream.h @@ -24,6 +24,8 @@ #include +#include + #include namespace filament { @@ -189,9 +191,10 @@ public: * The callback tales two arguments: the AHardwareBuffer and the userdata. * @param userdata Optional closure data. Filament will pass this into the callback when it * releases the image. + * @param transform Optional transform matrix to apply to the image. */ void setAcquiredImage(void* UTILS_NONNULL image, - Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata, math::mat3f const& transform = math::mat3f()) noexcept; /** * @see setAcquiredImage(void*, Callback, void*) @@ -202,10 +205,11 @@ public: * It callback tales two arguments: the AHardwareBuffer and the userdata. * @param userdata Optional closure data. Filament will pass this into the callback when it * releases the image. + * @param transform Optional transform matrix to apply to the image. */ void setAcquiredImage(void* UTILS_NONNULL image, backend::CallbackHandler* UTILS_NULLABLE handler, - Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata, math::mat3f const& transform = math::mat3f()) noexcept; /** * Updates the size of the incoming stream. Whether this value is used is diff --git a/filament/src/Stream.cpp b/filament/src/Stream.cpp index bcd9c1777b..1c83c971c5 100644 --- a/filament/src/Stream.cpp +++ b/filament/src/Stream.cpp @@ -24,13 +24,13 @@ StreamType Stream::getStreamType() const noexcept { return downcast(this)->getStreamType(); } -void Stream::setAcquiredImage(void* image, Callback const callback, void* userdata) noexcept { - downcast(this)->setAcquiredImage(image, callback, userdata); +void Stream::setAcquiredImage(void* image, Callback const callback, void* userdata, math::mat3f const& transform) noexcept { + downcast(this)->setAcquiredImage(image, callback, userdata, transform); } void Stream::setAcquiredImage(void* image, - CallbackHandler* handler, Callback const callback, void* userdata) noexcept { - downcast(this)->setAcquiredImage(image, handler, callback, userdata); + CallbackHandler* handler, Callback const callback, void* userdata, math::mat3f const& transform) noexcept { + downcast(this)->setAcquiredImage(image, handler, callback, userdata, transform); } void Stream::setDimensions(uint32_t const width, uint32_t const height) noexcept { diff --git a/filament/src/details/Stream.cpp b/filament/src/details/Stream.cpp index 00d2ddaed7..65e02d6712 100644 --- a/filament/src/details/Stream.cpp +++ b/filament/src/details/Stream.cpp @@ -95,13 +95,13 @@ void FStream::terminate(FEngine& engine) noexcept { } void FStream::setAcquiredImage(void* image, - Callback const callback, void* userdata) noexcept { - mEngine.getDriverApi().setAcquiredImage(mStreamHandle, image, nullptr, callback, userdata); + Callback const callback, void* userdata, math::mat3f const& transform) noexcept { + mEngine.getDriverApi().setAcquiredImage(mStreamHandle, image, transform, nullptr, callback, userdata); } void FStream::setAcquiredImage(void* image, - CallbackHandler* handler, Callback const callback, void* userdata) noexcept { - mEngine.getDriverApi().setAcquiredImage(mStreamHandle, image, handler, callback, userdata); + CallbackHandler* handler, Callback const callback, void* userdata, math::mat3f const& transform) noexcept { + mEngine.getDriverApi().setAcquiredImage(mStreamHandle, image, transform, handler, callback, userdata); } void FStream::setDimensions(uint32_t const width, uint32_t const height) noexcept { diff --git a/filament/src/details/Stream.h b/filament/src/details/Stream.h index 855a02708a..116e6ca17a 100644 --- a/filament/src/details/Stream.h +++ b/filament/src/details/Stream.h @@ -25,6 +25,8 @@ #include +#include + namespace filament { class FEngine; @@ -36,8 +38,8 @@ public: backend::Handle getHandle() const noexcept { return mStreamHandle; } - void setAcquiredImage(void* image, Callback callback, void* userdata) noexcept; - void setAcquiredImage(void* image, backend::CallbackHandler* handler, Callback callback, void* userdata) noexcept; + void setAcquiredImage(void* image, Callback callback, void* userdata, math::mat3f const& transform) noexcept; + void setAcquiredImage(void* image, backend::CallbackHandler* handler, Callback callback, void* userdata, math::mat3f const& transform) noexcept; void setDimensions(uint32_t width, uint32_t height) noexcept; From 0a0d4ed23aba3f28ce389428bd35d915c2c31a30 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Mon, 10 Mar 2025 12:49:58 -0700 Subject: [PATCH 18/21] Update HandleAllocator in test (#8508) --- filament/backend/test/test_Handles.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filament/backend/test/test_Handles.cpp b/filament/backend/test/test_Handles.cpp index 0ec954195b..695fb00bfd 100644 --- a/filament/backend/test/test_Handles.cpp +++ b/filament/backend/test/test_Handles.cpp @@ -27,10 +27,10 @@ using namespace filament::backend; static constexpr uint32_t HANDLE_HEAP_FLAG = 0x80000000u; static constexpr size_t POOL_SIZE_BYTES = 8 * 1024U * 1024U; // NOTE: actual count may be lower due to alignment requirements -constexpr size_t const POOL_HANDLE_COUNT = POOL_SIZE_BYTES / (32 + 96 + 136); // 31775 +constexpr size_t const POOL_HANDLE_COUNT = POOL_SIZE_BYTES / (32 + 96 + 184); // 31775 // This must match HandleAllocatorGL, so its implementation is present on all platforms. -#define HandleAllocatorTest HandleAllocator<32, 96, 136> // ~4520 / pool / MiB +#define HandleAllocatorTest HandleAllocator<32, 96, 184> // ~4520 / pool / MiB struct MyHandle { }; From 0bcb45613e126c0087ab3621300d87311fa46398 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 10 Mar 2025 22:11:58 +0000 Subject: [PATCH 19/21] Release Filament 1.58.0 --- NEW_RELEASE_NOTES.md | 1 - README.md | 4 ++-- RELEASE_NOTES.md | 4 ++++ android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 63090f0235..4a1a9c7fa7 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,4 +7,3 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut -- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**] diff --git a/README.md b/README.md index a9369d7d01..54795d7a83 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.57.2' + implementation 'com.google.android.filament:filament-android:1.58.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.57.2' +pod 'Filament', '~> 1.58.0' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index bed2c35ed9..74bf74a1d3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,10 @@ 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.58.1 + +- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**] + ## v1.57.3 - android: breaking changes to API KTX1Loader::createIndirectLight and KTX1Loader::createSkybox diff --git a/android/gradle.properties b/android/gradle.properties index e482e6fd0b..3833fd5bca 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.57.2 +VERSION_NAME=1.58.0 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index c4fbd00878..af2ff75e12 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.57.2" + spec.version = "1.58.0" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.57.2/filament-v1.57.2-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.0/filament-v1.58.0-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 155e4911c0..8445d243a7 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.57.2", + "version": "1.58.0", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From cec7150b4c4e190b49ba16ddf0f2398b8ee8e150 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 10 Mar 2025 22:12:21 +0000 Subject: [PATCH 20/21] Bump version to 1.58.1 --- README.md | 4 ++-- android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 54795d7a83..ce0adf1558 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.58.0' + implementation 'com.google.android.filament:filament-android:1.58.1' } ``` @@ -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.58.0' +pod 'Filament', '~> 1.58.1' ``` ## Documentation diff --git a/android/gradle.properties b/android/gradle.properties index 3833fd5bca..3007050a8a 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.58.0 +VERSION_NAME=1.58.1 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index af2ff75e12..23a0c603c1 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.58.0" + spec.version = "1.58.1" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.0/filament-v1.58.0-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.1/filament-v1.58.1-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 8445d243a7..d739c8380b 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.58.0", + "version": "1.58.1", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From d53abebbe991426377b3b5e5af849b5a762670ab Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 17 Mar 2025 08:58:24 -0700 Subject: [PATCH 21/21] Bump MATERIAL_VERSION to 58 --- libs/filabridge/include/filament/MaterialEnums.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index f5676640fe..2800bd64d4 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -28,7 +28,7 @@ namespace filament { // update this when a new version of filament wouldn't work with older materials -static constexpr size_t MATERIAL_VERSION = 57; +static constexpr size_t MATERIAL_VERSION = 58; /** * Supported shading models