From 1f1389e668e83e1041096d4acc493428d462375b Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 19 Dec 2024 10:00:51 -0800 Subject: [PATCH 01/11] Metal: avoid crashing for invalid programs (#8321) --- filament/backend/src/metal/MetalContext.h | 1 + filament/backend/src/metal/MetalDriver.mm | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index 1584351508..f85e08545b 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -155,6 +155,7 @@ struct MetalContext { RenderPassFlags currentRenderPassFlags; MetalRenderTarget* currentRenderTarget = nullptr; + bool validPipelineBound = false; // State trackers. PipelineStateTracker pipelineState; diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index d787c0cdb2..5bc2002ec7 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1657,6 +1657,7 @@ void MetalDriver::bindPipeline(PipelineState const& ps) { // during the draw call when the program is invalid. The shader compile error has already been // dumped to the console at this point, so it's fine to simply return early. if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!functions)) { + mContext->validPipelineBound = false; return; } @@ -1789,6 +1790,8 @@ void MetalDriver::bindPipeline(PipelineState const& ps) { clamp:0.0]; mContext->currentPolygonOffset = ps.polygonOffset; } + + mContext->validPipelineBound = true; } void MetalDriver::bindRenderPrimitive(Handle rph) { @@ -1886,6 +1889,10 @@ void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t inst << "draw() without a valid command encoder."; DEBUG_LOG("draw2(...)\n"); + if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!mContext->validPipelineBound)) { + return; + } + // Bind the offset data. if (mContext->dynamicOffsets.isDirty()) { const auto [size, data] = mContext->dynamicOffsets.getOffsets(); From aa09d86b5a3788c62ec389941102b1770dfbd983 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Thu, 19 Dec 2024 12:14:08 -0800 Subject: [PATCH 02/11] matdbg: Fix material collision (#8322) Fix 3 bugs wrt matdbg: 1. The numbering scheme for materials with same name was buggy 2. The shared depth variants of the default material should also show up as active material variants. 3. When two instantiation of FMaterial point to the exact same bits, we still need to treat them as two materials. (Otherwise we wouldn't be able to modify one of them in matdbg). --- filament/src/details/Material.cpp | 9 +++------ filament/src/details/Material.h | 12 ++++++++++++ libs/matdbg/src/DebugServer.cpp | 8 ++++++-- libs/matdbg/web/app.js | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 651b88cf02..be8ca04be2 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -611,13 +611,10 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexce FEngine const& engine = mEngine; DriverApi& driverApi = mEngine.getDriverApi(); - bool const isSharedVariant = - (mMaterialDomain == MaterialDomain::SURFACE) && - !mIsDefaultMaterial && !mHasCustomDepthShader && - Variant::isValidDepthVariant(variant); + bool const isShared = isSharedVariant(variant); // Check if the default material has this program cached - if (isSharedVariant) { + if (isShared) { FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial(); if (pDefaultMaterial) { auto program = pDefaultMaterial->mCachedPrograms[variant.key]; @@ -636,7 +633,7 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexce // If the default material doesn't already have this program cached, and all caching conditions // are met (Surface Domain and no custom depth shader), cache it now. // New Materials will inherit these program automatically. - if (isSharedVariant) { + if (isShared) { FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial(); if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) { // set the tag to the default material name diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index eb578be3a3..5dd55e733e 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -156,6 +156,13 @@ public: std::unique_lock lock(mActiveProgramsLock); mActivePrograms.set(variant.key); lock.unlock(); + + if (isSharedVariant(variant)) { + FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial(); + if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[variant.key]) { + return pDefaultMaterial->getProgram(variant); + } + } #endif assert_invariant(mCachedPrograms[variant.key]); return mCachedPrograms[variant.key]; @@ -290,6 +297,11 @@ private: void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept; + inline bool isSharedVariant(Variant variant) const { + return (mMaterialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial && + !mHasCustomDepthShader && Variant::isValidDepthVariant(variant); + } + // try to order by frequency of use mutable std::array, VARIANT_COUNT> mCachedPrograms; DescriptorSetLayout mPerViewDescriptorSetLayout; diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index 96c9538620..803cf00fba 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -193,8 +193,12 @@ DebugServer::addMaterial(const CString& name, const void* data, size_t size, voi return {}; } - const uint32_t seed = 42; - const MaterialKey key = utils::hash::murmurSlow((const uint8_t*) data, size, seed); + // Note that it's possible to have two materials with the exact same content (however wasteful), + // but they refer to different instantiation of FMaterial. Hence we hash on userdata and the + // material data. + constexpr uint32_t seed = 42; + uint64_t dataSpace[2] = {(uint64_t) data, (uint64_t) userdata}; + uint32_t const key = utils::hash::murmur3((const uint32_t*) dataSpace, sizeof(dataSpace), seed); // Retain a copy of the package to permit queries after the client application has // freed up the original material package. diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index 4a7c7df4e4..cccec2b1b6 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -662,8 +662,8 @@ class MaterialSidePanel extends LitElement { let name = material.name || kUntitledPlaceholder; if (name in duplicatedLabels) { const index = duplicatedLabels[name]; - name = `${name} (${index})`; duplicatedLabels[name] = index + 1; + name = `${name} (${index})`; } return { matid: matid, From 757e3c57d8ae0c73854a04210742d9415faa3ac2 Mon Sep 17 00:00:00 2001 From: Doris Wu Date: Fri, 20 Dec 2024 23:20:54 +0800 Subject: [PATCH 03/11] Add skeleton code of fgviewer (#8303) * Skeleton of fgviewer debug server * Update the map for fg info * Add ApiHandler skeleton class * Format the files Format the file * Prevent fgviewer being built before ready Add comment to fgviewer related lines Fix cmake commands * Update the copyright * Address the comments Address the comments * Address the comments * Specify the debug server * Fix build options --- CMakeLists.txt | 10 +- android/build.gradle | 10 ++ android/filament-android/CMakeLists.txt | 11 ++ build.sh | 39 +++++- filament/CMakeLists.txt | 7 + libs/fgviewer/CMakeLists.txt | 71 ++++++++++ libs/fgviewer/include/fgviewer/DebugServer.h | 88 +++++++++++++ libs/fgviewer/include/fgviewer/JsonWriter.h | 45 +++++++ libs/fgviewer/src/ApiHandler.cpp | 69 ++++++++++ libs/fgviewer/src/ApiHandler.h | 49 +++++++ libs/fgviewer/src/DebugServer.cpp | 131 +++++++++++++++++++ 11 files changed, 528 insertions(+), 2 deletions(-) create mode 100644 libs/fgviewer/CMakeLists.txt create mode 100644 libs/fgviewer/include/fgviewer/DebugServer.h create mode 100644 libs/fgviewer/include/fgviewer/JsonWriter.h create mode 100644 libs/fgviewer/src/ApiHandler.cpp create mode 100644 libs/fgviewer/src/ApiHandler.h create mode 100644 libs/fgviewer/src/DebugServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 649577b396..b8462d29f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,11 +525,14 @@ else() option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" OFF) endif() -# By default, link in matdbg for Desktop + Debug only since it pulls in filamat and a web server. +# By default, link in matdbg/fgviewer for Desktop + Debug only since it pulls in filamat and a web server. if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND IS_HOST_PLATFORM) option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" ON) + # TODO: Uncomment below when fgviewer is ready + # option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" ON) else() option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" OFF) + option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" OFF) endif() # Only optimize materials in Release mode (so error message lines match the source code) @@ -778,6 +781,11 @@ if (FILAMENT_BUILD_FILAMAT OR IS_HOST_PLATFORM) if (FILAMENT_ENABLE_MATDBG OR IS_HOST_PLATFORM) add_subdirectory(${LIBRARIES}/matdbg) endif() + + # TODO: Uncomment below when fgviewer is ready + # if (FILAMENT_ENABLE_FGVIEWER OR IS_HOST_PLATFORM) + # add_subdirectory(${LIBRARIES}/fgviewer) + # endif() endif() if (FILAMENT_SUPPORTS_VULKAN) diff --git a/android/build.gradle b/android/build.gradle index 970e41fb90..293387890e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,6 +11,9 @@ // com.google.android.filament.exclude-vulkan // When set, support for Vulkan will be excluded. // +// com.google.android.filament.fgviewer +// When set, enables fgviewer +// // com.google.android.filament.matdbg // When set, enables matdbg // @@ -61,6 +64,11 @@ buildscript { .gradleProperty("com.google.android.filament.exclude-vulkan") .isPresent() + // TODO: Uncomment below when fgviewer is ready + // def fgviewer = providers + // .gradleProperty("com.google.android.filament.fgviewer") + // .isPresent() + def matdbg = providers .gradleProperty("com.google.android.filament.matdbg") .isPresent() @@ -115,6 +123,8 @@ buildscript { "-DANDROID_STL=c++_static", "-DFILAMENT_DIST_DIR=${filamentPath}".toString(), "-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(), + // TODO: Uncomment below when fgviewer is ready + // "-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 7f3122f645..21da97e6b7 100644 --- a/android/filament-android/CMakeLists.txt +++ b/android/filament-android/CMakeLists.txt @@ -2,6 +2,8 @@ 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_MATDBG "Enables Material debugger" OFF) option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF) @@ -51,6 +53,13 @@ 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_MATDBG) add_library(matdbg STATIC IMPORTED) set_target_properties(matdbg PROPERTIES IMPORTED_LOCATION @@ -117,6 +126,8 @@ target_link_libraries(filament-jni # libgeometry is PUBLIC because gltfio uses it. PUBLIC geometry + # TODO: Uncomment below when fgviewer is ready + # $<$:fgviewer> $<$:matdbg> $<$:filamat> $<$:bluevk> diff --git a/build.sh b/build.sh index 8c5d94a96d..3f972d75c1 100755 --- a/build.sh +++ b/build.sh @@ -23,6 +23,8 @@ function print_help { echo " This is sometimes needed instead of -c (which still misses some clean steps)." echo " -d" echo " Enable matdbg." + echo " -t" + echo " Enable fgviewer." echo " -f" echo " Always invoke CMake before incremental builds." echo " -g" @@ -125,6 +127,27 @@ function print_matdbg_help { echo "" } +function print_fgviewer_help { + echo "fgviewer is enabled in the build, but some extra steps are needed." + echo "" + echo "FOR DESKTOP BUILDS:" + echo "" + echo "Please set the port environment variable before launching. e.g., on macOS do:" + echo " export FILAMENT_FGVIEWER_PORT=8085" + echo "" + echo "FOR ANDROID BUILDS:" + echo "" + echo "1) For Android Studio builds, make sure to set:" + echo " -Pcom.google.android.filament.fgviewer" + echo " option in Preferences > Build > Compiler > Command line options." + echo "" + echo "2) The port number is hardcoded to 8085 so you will need to do:" + echo " adb forward tcp:8085 tcp:8085" + echo "" + echo "3) Be sure to enable INTERNET permission in your app's manifest file." + echo "" +} + # Unless explicitly specified, NDK version will be selected as highest available version within same major release chain FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")} @@ -172,6 +195,7 @@ VULKAN_ANDROID_GRADLE_OPTION="" EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF" MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF" +FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF" MATDBG_GRADLE_OPTION="" MATOPT_OPTION="" @@ -240,6 +264,7 @@ function build_desktop_target { -DCMAKE_BUILD_TYPE="$1" \ -DCMAKE_INSTALL_PREFIX="../${lc_target}/filament" \ ${EGL_ON_LINUX_OPTION} \ + ${FGVIEWER_OPTION} \ ${MATDBG_OPTION} \ ${MATOPT_OPTION} \ ${ASAN_UBSAN_OPTION} \ @@ -376,6 +401,7 @@ function build_android_target { -DFILAMENT_NDK_VERSION="${FILAMENT_NDK_VERSION}" \ -DCMAKE_INSTALL_PREFIX="../android-${lc_target}/filament" \ -DCMAKE_TOOLCHAIN_FILE="../../build/toolchain-${arch}-linux-android.cmake" \ + ${FGVIEWER_OPTION} \ ${MATDBG_OPTION} \ ${MATOPT_OPTION} \ ${VULKAN_ANDROID_OPTION} \ @@ -613,6 +639,7 @@ function build_ios_target { -DPLATFORM_NAME="${platform}" \ -DIOS=1 \ -DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \ + ${FGVIEWER_OPTION} \ ${MATDBG_OPTION} \ ${MATOPT_OPTION} \ ${STEREOSCOPIC_OPTION} \ @@ -802,7 +829,7 @@ function check_debug_release_build { pushd "$(dirname "$0")" > /dev/null -while getopts ":hacCfgijmp:q:uvslwedk:bx:S:X:" opt; do +while getopts ":hacCfgijmp:q:uvslwedtk:bx:S:X:" opt; do case ${opt} in h) print_help @@ -823,6 +850,12 @@ while getopts ":hacCfgijmp:q:uvslwedk:bx:S:X:" opt; do MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_BUILD_FILAMAT=ON" MATDBG_GRADLE_OPTION="-Pcom.google.android.filament.matdbg" ;; + t) + # TODO: Uncomment below when fgviewer is ready + # PRINT_FGVIEWER_HELP=true + # FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=ON" + #FGVIEWER_GRADLE_OPTION="-Pcom.google.android.filament.fgviewer" + ;; f) ISSUE_CMAKE_ALWAYS=true ;; @@ -1027,3 +1060,7 @@ fi if [[ "${PRINT_MATDBG_HELP}" == "true" ]]; then print_matdbg_help fi + +if [[ "${PRINT_FGVIEWER_HELP}" == "true" ]]; then + print_fgviewer_help +fi diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 82e336215d..d218a39170 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -561,6 +561,13 @@ target_link_libraries(${TARGET} PUBLIC filaflat) target_link_libraries(${TARGET} PUBLIC filabridge) target_link_libraries(${TARGET} PUBLIC ibl-lite) +if (FILAMENT_ENABLE_FGVIEWER) + target_link_libraries(${TARGET} PUBLIC fgviewer) + add_definitions(-DFILAMENT_ENABLE_FGVIEWER=1) +else() + add_definitions(-DFILAMENT_ENABLE_FGVIEWER=0) +endif() + if (FILAMENT_ENABLE_MATDBG) target_link_libraries(${TARGET} PUBLIC matdbg) add_definitions(-DFILAMENT_ENABLE_MATDBG=1) diff --git a/libs/fgviewer/CMakeLists.txt b/libs/fgviewer/CMakeLists.txt new file mode 100644 index 0000000000..cf6bdb526d --- /dev/null +++ b/libs/fgviewer/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.19) +project(fgviewer C ASM) + +set(TARGET fgviewer) +set(PUBLIC_HDR_DIR include) + +if (CMAKE_CROSSCOMPILING) + include(${IMPORT_EXECUTABLES}) +endif() + +# ================================================================================================== +# Sources and headers +# ================================================================================================== + +set(PUBLIC_HDRS + include/fgviewer/DebugServer.h + include/fgviewer/JsonWriter.h +) + +set(SRCS + src/ApiHandler.cpp + src/ApiHandler.h + src/DebugServer.cpp +) + +# ================================================================================================== +# Include and target definitions +# ================================================================================================== + +include_directories(${PUBLIC_HDR_DIR}) + +add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS}) + +target_link_libraries(${TARGET} PUBLIC + civetweb + utils +) + +target_include_directories(${TARGET} PRIVATE ${filamat_SOURCE_DIR}/src) + +target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR}) +set_target_properties(${TARGET} PROPERTIES FOLDER Libs) + +# ================================================================================================== +# Compiler flags +# ================================================================================================== + +if (MSVC) +else() + target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register) +endif() + +# ================================================================================================== +# Installation +# ================================================================================================== + +# matdbg 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. +set(FGVIEWER_DEPS + fgviewer + civetweb + ) + +set(FGVIEWER_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libfgviewer_combined.a") +combine_static_libs(fgviewer "${FGVIEWER_COMBINED_OUTPUT}" "${FGVIEWER_DEPS}") + +set(FGVIEWER_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}fgviewer${CMAKE_STATIC_LIBRARY_SUFFIX}) +install(FILES "${FGVIEWER_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${FGVIEWER_LIB_NAME}) +# We do not need fgviewer headers in the install directory +# install(DIRECTORY ${PUBLIC_HDR_DIR}/fgviewer DESTINATION include) diff --git a/libs/fgviewer/include/fgviewer/DebugServer.h b/libs/fgviewer/include/fgviewer/DebugServer.h new file mode 100644 index 0000000000..ef05448333 --- /dev/null +++ b/libs/fgviewer/include/fgviewer/DebugServer.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2024 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 FGVIEWER_DEBUGSERVER_H +#define FGVIEWER_DEBUGSERVER_H + +#include +#include + +#include +#include + +class CivetServer; + +namespace filament::fgviewer { + +using FrameGraphInfoKey = uint32_t; + +struct FrameGraphPassInfo { + utils::CString pass_name; + // TODO: Add struct detail properties +}; + +struct FrameGraphInfo { + utils::CString view_name; + std::vector passes; +}; + +/** + * Server-side frame graph debugger. + * + * This class manages an HTTP server. It receives frame graph packages from the Filament C++ engine or + * from a standalone tool such as fginfo. + */ +class DebugServer { +public: + static std::string_view const kSuccessHeader; + static std::string_view const kErrorHeader; + + DebugServer(int port); + ~DebugServer(); + + /** + * Notifies the debugger that a new view has been added. + */ + void addView(const utils::CString& name, FrameGraphInfo info); + + /** + * Notifies the debugger that the given view has been deleted. + */ + void removeView(const utils::CString& name); + + /** + * Updates the information for a given view. + */ + void updateView(const utils::CString& name, FrameGraphInfo info); + + bool isReady() const { return mServer; } + +private: + CivetServer* mServer; + + std::unordered_map mViews; + mutable utils::Mutex mViewsMutex; + + class FileRequestHandler* mFileHandler = nullptr; + class ApiHandler* mApiHandler = nullptr; + + friend class FileRequestHandler; + friend class ApiHandler; +}; + +} // namespace filament::fgviewer + +#endif // FGVIEWER_DEBUGSERVER_H diff --git a/libs/fgviewer/include/fgviewer/JsonWriter.h b/libs/fgviewer/include/fgviewer/JsonWriter.h new file mode 100644 index 0000000000..de9c188eee --- /dev/null +++ b/libs/fgviewer/include/fgviewer/JsonWriter.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 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 FGVIEWER_JSONWRITER_H +#define FGVIEWER_JSONWRITER_H + +#include + +namespace filament::fgviewer { + +struct FrameGraphInfo; + +// This class generates portions of JSON messages that are sent to the web client. +// Note that some portions of these JSON strings are generated by directly in DebugServer, +// as well as CommonWriter. +class JsonWriter { +public: + + // Retrieves the most recently generated string. + const char* getJsonString() const; + size_t getJsonSize() const; + + // Generates a JSON string describing the given FrameGraphInfo. + bool writeFrameGraphInfo(const FrameGraphInfo& frameGraph); + +private: + utils::CString mJsonString; +}; + +} // namespace filament::fgviewer + +#endif // FGVIEWER_JSONWRITER_H diff --git a/libs/fgviewer/src/ApiHandler.cpp b/libs/fgviewer/src/ApiHandler.cpp new file mode 100644 index 0000000000..729820d404 --- /dev/null +++ b/libs/fgviewer/src/ApiHandler.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024 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 "ApiHandler.h" + +#include + +#include +#include + +#include + +namespace filament::fgviewer { + +using namespace std::chrono_literals; + +namespace { + +auto const& kSuccessHeader = DebugServer::kSuccessHeader; +auto const& kErrorHeader = DebugServer::kErrorHeader; + +auto const error = [](int line, std::string const& uri) { + utils::slog.e << "[fgviewer] DebugServer: 404 at line " << line << ": " << uri << utils::io::endl; + return false; +}; + +} // anonymous + +bool ApiHandler::handleGetApiFgInfo(struct mg_connection* conn, + struct mg_request_info const* request) { + auto const softError = [conn, request](char const* msg) { + utils::slog.e << "[fgviewer] DebugServer: " << msg << ": " << request->query_string << utils::io::endl; + mg_printf(conn, kErrorHeader.data(), "application/txt"); + mg_write(conn, msg, strlen(msg)); + return true; + }; + + // TODO: Implement the method + return true; +} + +void ApiHandler::addFrameGraph(FrameGraphInfo const* framegraph) { + // TODO: Implement the method +} + + +bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { + struct mg_request_info const* request = mg_get_request_info(conn); + std::string const& uri = request->local_uri; + + // TODO: Implement the method + return true; +} + +} // filament::fgviewer diff --git a/libs/fgviewer/src/ApiHandler.h b/libs/fgviewer/src/ApiHandler.h new file mode 100644 index 0000000000..b0ed9e785d --- /dev/null +++ b/libs/fgviewer/src/ApiHandler.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 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 FGVIEWER_APIHANDLER_H +#define FGVIEWER_APIHANDLER_H + +#include + +namespace filament::fgviewer { + +class DebugServer; +struct FrameGraphInfo; + +// Handles the following REST requests, where {id} is an 8-digit hex string. +// +// GET /api/framegraphs +// GET /api/framegraph?fg={viewname} +// +class ApiHandler : public CivetHandler { +public: + explicit ApiHandler(DebugServer* server) + : mServer(server) {} + ~ApiHandler() = default; + + bool handleGet(CivetServer* server, struct mg_connection* conn); + void addFrameGraph(FrameGraphInfo const* frameGraph); + +private: + bool handleGetApiFgInfo(struct mg_connection* conn, struct mg_request_info const* request); + + DebugServer* mServer; +}; + +} // filament::fgviewer + +#endif // FGVIEWER_APIHANDLER_H diff --git a/libs/fgviewer/src/DebugServer.cpp b/libs/fgviewer/src/DebugServer.cpp new file mode 100644 index 0000000000..ce1ccaa36b --- /dev/null +++ b/libs/fgviewer/src/DebugServer.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 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 + +#include "ApiHandler.h" + +#include + +#include +#include +#include + +#include +#include + +namespace filament::fgviewer { + +namespace { +std::string const BASE_URL = "libs/fgviewer/web"; + +FrameGraphInfoKey getKeybyString(const utils::CString &input, + uint32_t seed) { + return utils::hash::murmurSlow(reinterpret_cast( + input.c_str()), input.size(), 0); +} +} // anonymous + +using namespace utils; + +std::string_view const DebugServer::kSuccessHeader = + "HTTP/1.1 200 OK\r\nContent-Type: %s\r\n" + "Connection: close\r\n\r\n"; + +std::string_view const DebugServer::kErrorHeader = + "HTTP/1.1 404 Not Found\r\nContent-Type: %s\r\n" + "Connection: close\r\n\r\n"; + +class FileRequestHandler : public CivetHandler { +public: + FileRequestHandler(DebugServer* server) : mServer(server) {} + bool handleGet(CivetServer *server, struct mg_connection *conn) { + auto const& kSuccessHeader = DebugServer::kSuccessHeader; + struct mg_request_info const* request = mg_get_request_info(conn); + std::string uri(request->request_uri); + if (uri == "/") { + uri = "/index.html"; + } + + if (uri == "/index.html" || uri == "/app.js" || uri == "/api.js") { + mg_send_file(conn, (BASE_URL + uri).c_str()); + return true; + } + slog.e << "[fgviewer] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl; + return false; + } +private: + DebugServer* mServer; +}; + +DebugServer::DebugServer(int port) { + // 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 + // (CSS, JavaScript, images, ...)." If this count is too small, the web app basically hangs. + const char* kServerOptions[] = { + "listening_ports", "8085", + "num_threads", "10", + "error_log_file", "civetweb.txt", + nullptr + }; + std::string portString = std::to_string(port); + kServerOptions[1] = portString.c_str(); + + mServer = new CivetServer(kServerOptions); + if (!mServer->getContext()) { + delete mServer; + mServer = nullptr; + slog.e << "[fgviewer] Unable to start DebugServer, see civetweb.txt for details." << io::endl; + return; + } + + mFileHandler = new FileRequestHandler(this); + mApiHandler = new ApiHandler(this); + + mServer->addHandler("/api", mApiHandler); + mServer->addHandler("", mFileHandler); + + slog.i << "[fgviewer] DebugServer listening at http://localhost:" << port << io::endl; +} + +DebugServer::~DebugServer() { + mServer->close(); + + delete mFileHandler; + delete mApiHandler; + delete mServer; +} + +void DebugServer::addView(const utils::CString &name, FrameGraphInfo info) { + std::unique_lock lock(mViewsMutex); + const FrameGraphInfoKey key = getKeybyString(name, 0); + mViews.insert({key, info}); +} + +void DebugServer::removeView(const utils::CString& name) { + std::unique_lock lock(mViewsMutex); + const FrameGraphInfoKey key = getKeybyString(name, 0); + mViews.erase(key); +} + +void DebugServer::updateView(const utils::CString& name, FrameGraphInfo info) { + std::unique_lock lock(mViewsMutex); + const FrameGraphInfoKey key = getKeybyString(name, 0); + mViews[key] = info; +} + +} // namespace filament::fgviewer From 8c1e028b46721fb2dfb953a97d13d32a3298dec9 Mon Sep 17 00:00:00 2001 From: seker <04070628@163.com> Date: Tue, 31 Dec 2024 03:42:18 +0800 Subject: [PATCH 04/11] Fix : null pointer crash (#8326) --- NEW_RELEASE_NOTES.md | 1 + libs/gltfio/src/Animator.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..ee533ab018 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 +fix crash: the 'target_node' of Animation Channel may be nullpointer. \ No newline at end of file diff --git a/libs/gltfio/src/Animator.cpp b/libs/gltfio/src/Animator.cpp index 0d8b667644..7b1bd6eb25 100644 --- a/libs/gltfio/src/Animator.cpp +++ b/libs/gltfio/src/Animator.cpp @@ -408,6 +408,9 @@ void AnimatorImpl::addChannels(const FixedCapacityVector& nodeMap, const Sampler* samplers = dst.samplers.data(); for (cgltf_size j = 0, nchans = srcAnim.channels_count; j < nchans; ++j) { const cgltf_animation_channel& srcChannel = srcChannels[j]; + if (!srcChannel.target_node) { + continue; + } Entity targetEntity = nodeMap[srcChannel.target_node - nodes]; if (UTILS_UNLIKELY(!targetEntity)) { if (GLTFIO_VERBOSE) { From 7d0b6526633e05c0f456dc67d203602a4de2334b Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Mon, 6 Jan 2025 10:33:25 -0800 Subject: [PATCH 05/11] matdbg: fix two memory bugs (#8337) - murmur3 expects word size not byte size - should use uint8_t in addressing blob source. both would crash when asan is enabled. --- libs/matdbg/src/DebugServer.cpp | 2 +- libs/matdbg/src/ShaderReplacer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index 803cf00fba..e8efb0b227 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -198,7 +198,7 @@ DebugServer::addMaterial(const CString& name, const void* data, size_t size, voi // material data. constexpr uint32_t seed = 42; uint64_t dataSpace[2] = {(uint64_t) data, (uint64_t) userdata}; - uint32_t const key = utils::hash::murmur3((const uint32_t*) dataSpace, sizeof(dataSpace), seed); + uint32_t const key = utils::hash::murmurSlow((uint8_t const*) dataSpace, sizeof(dataSpace), seed); // Retain a copy of the package to permit queries after the client application has // freed up the original material package. diff --git a/libs/matdbg/src/ShaderReplacer.cpp b/libs/matdbg/src/ShaderReplacer.cpp index 2a99ee0db5..8a457e598c 100644 --- a/libs/matdbg/src/ShaderReplacer.cpp +++ b/libs/matdbg/src/ShaderReplacer.cpp @@ -377,7 +377,7 @@ void BlobIndex::writeChunks(ostream& stream) { for (auto& record : mShaderRecords) { const auto& src = mDataBlobs[record.dictionaryIndex]; assert(src.size() % 4 == 0); - const uint32_t* ptr = (const uint32_t*) src.data(); + uint8_t const* ptr = (uint8_t const*) src.data(); record.dictionaryIndex = blobs.addBlob(vector(ptr, ptr + src.size())); } From 7d271cea1d561752386995adff3c40769d78f6c5 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 18 Dec 2024 15:13:58 -0800 Subject: [PATCH 06/11] remove backend deprecated and unused APIs --- .../include/private/backend/DriverAPI.inc | 11 ------ filament/backend/src/metal/MetalDriver.mm | 4 --- filament/backend/src/noop/NoopDriver.cpp | 6 ---- filament/backend/src/opengl/OpenGLDriver.cpp | 35 +++++++------------ filament/backend/src/vulkan/VulkanDriver.cpp | 7 ---- 5 files changed, 13 insertions(+), 50 deletions(-) diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 66556b0f41..9aaf381fc0 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -399,17 +399,6 @@ DECL_DRIVER_API_N(update3DImage, DECL_DRIVER_API_N(generateMipmaps, backend::TextureHandle, th) -// Deprecated -DECL_DRIVER_API_N(setExternalImage, - backend::TextureHandle, th, - void*, image) - -// Deprecated -DECL_DRIVER_API_N(setExternalImagePlane, - backend::TextureHandle, th, - void*, image, - uint32_t, plane) - DECL_DRIVER_API_N(setExternalStream, backend::TextureHandle, th, backend::StreamHandle, sh) diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 5bc2002ec7..0972f3491e 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1191,10 +1191,6 @@ void MetalDriver::setupExternalImage(void* image) { CVPixelBufferRetain(pixelBuffer); } -void MetalDriver::setExternalImage(Handle th, void* image) {} - -void MetalDriver::setExternalImagePlane(Handle th, void* image, uint32_t plane) {} - void MetalDriver::setExternalStream(Handle th, Handle sh) { } diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index afc5ac808d..4f26222dc3 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -265,12 +265,6 @@ TimerQueryResult NoopDriver::getTimerQueryValue(Handle tqh, uint64 return TimerQueryResult::ERROR; } -void NoopDriver::setExternalImage(Handle th, void* image) { -} - -void NoopDriver::setExternalImagePlane(Handle th, void* image, uint32_t plane) { -} - void NoopDriver::setExternalStream(Handle th, Handle sh) { } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 79580fc7c4..7ee4f5a3ab 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -1054,15 +1054,25 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle th, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) { + DEBUG_MARKER() createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage); - setExternalImage(th, image); + + GLTexture* t = handle_cast(th); + assert_invariant(t); + assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL); + + bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); + if (mPlatform.setExternalImage(image, t->externalTexture)) { + // the target and id can be reset each time + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + } } void OpenGLDriver::createTextureExternalImagePlaneR(Handle th, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image, uint32_t plane) { - createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage); - setExternalImagePlane(th, image, plane); + // not relevant for the OpenGL backend } void OpenGLDriver::importTextureR(Handle th, intptr_t id, @@ -2774,25 +2784,6 @@ void OpenGLDriver::setupExternalImage(void* image) { mPlatform.retainExternalImage(image); } -void OpenGLDriver::setExternalImage(Handle th, void* image) { - DEBUG_MARKER() - GLTexture* t = handle_cast(th); - assert_invariant(t); - assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL); - - bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); - if (mPlatform.setExternalImage(image, t->externalTexture)) { - // the target and id can be reset each time - t->gl.target = t->externalTexture->target; - t->gl.id = t->externalTexture->id; - bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); - } -} - -void OpenGLDriver::setExternalImagePlane(Handle th, void* image, uint32_t plane) { - DEBUG_MARKER() -} - void OpenGLDriver::setExternalStream(Handle th, Handle sh) { auto& gl = mContext; if (gl.ext.OES_EGL_image_external_essl3) { diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 25a2448b29..3e7238c1e5 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1189,13 +1189,6 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle tqh, uint return TimerQueryResult::AVAILABLE; } -void VulkanDriver::setExternalImage(Handle th, void* image) { - -} - -void VulkanDriver::setExternalImagePlane(Handle th, void* image, uint32_t plane) { -} - void VulkanDriver::setExternalStream(Handle th, Handle sh) { } From ef6ef784c90581bd2f1e75d5b6fb1deaa0d92cde Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 18 Dec 2024 16:12:07 -0800 Subject: [PATCH 07/11] external textures are no longer restricted to SAMPLER_EXTERNAL OpenGLES allows this when GL_OES_EGL_image is present. --- .../filament-android/src/main/cpp/Texture.cpp | 7 +++ .../com/google/android/filament/Texture.java | 14 ++++++ .../include/private/backend/DriverAPI.inc | 1 + filament/backend/src/metal/MetalDriver.mm | 4 +- .../backend/src/opengl/GLDescriptorSet.cpp | 7 +-- filament/backend/src/opengl/GLDescriptorSet.h | 12 +++-- filament/backend/src/opengl/GLTexture.h | 7 +-- filament/backend/src/opengl/OpenGLContext.h | 8 +-- filament/backend/src/opengl/OpenGLDriver.cpp | 37 +++++++++++--- .../src/opengl/platforms/PlatformEGL.cpp | 12 +++-- filament/backend/src/vulkan/VulkanDriver.cpp | 3 +- .../backend/test/test_RenderExternalImage.cpp | 3 +- filament/include/filament/Texture.h | 16 +++++- filament/src/details/Texture.cpp | 50 +++++++++++-------- filament/src/details/Texture.h | 3 +- web/filament-js/jsbindings.cpp | 2 + 16 files changed, 135 insertions(+), 51 deletions(-) diff --git a/android/filament-android/src/main/cpp/Texture.cpp b/android/filament-android/src/main/cpp/Texture.cpp index ef778056c0..ff3fd36d26 100644 --- a/android/filament-android/src/main/cpp/Texture.cpp +++ b/android/filament-android/src/main/cpp/Texture.cpp @@ -138,6 +138,13 @@ Java_com_google_android_filament_Texture_nBuilderImportTexture(JNIEnv*, jclass, builder->import((intptr_t)id); } +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_Texture_nBuilderExternal(JNIEnv*, jclass, jlong nativeBuilder) { + Texture::Builder *builder = (Texture::Builder *) nativeBuilder; + builder->external(); +} + extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jlong nativeEngine) { diff --git a/android/filament-android/src/main/java/com/google/android/filament/Texture.java b/android/filament-android/src/main/java/com/google/android/filament/Texture.java index 1cb732af13..eaf81adc3c 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Texture.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Texture.java @@ -800,6 +800,19 @@ public class Texture { return this; } + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * @return This Builder, for chaining calls. + */ + @NonNull + public Builder external() { + nBuilderExternal(mNativeBuilder); + return this; + } + /** * Creates a new Texture instance. * @param engine The {@link Engine} to associate this Texture with. @@ -1261,6 +1274,7 @@ public class Texture { private static native void nBuilderUsage(long nativeBuilder, int flags); private static native void nBuilderSwizzle(long nativeBuilder, int r, int g, int b, int a); private static native void nBuilderImportTexture(long nativeBuilder, long id); + private static native void nBuilderExternal(long nativeBuilder); private static native long nBuilderBuild(long nativeBuilder, long nativeEngine); private static native int nGetWidth(long nativeTexture, int level); diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 9aaf381fc0..6b951da975 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -214,6 +214,7 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle, backend::TextureSwizzle, a) DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage, + backend::SamplerType, target, backend::TextureFormat, format, uint32_t, width, uint32_t, height, diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 0972f3491e..38b9b6e0d3 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -482,7 +482,9 @@ void MetalDriver::createTextureViewSwizzleR(Handle th, Handletextures.insert(construct_handle(th, *mContext, src, r, g, b, a)); } -void MetalDriver::createTextureExternalImageR(Handle th, backend::TextureFormat format, +void MetalDriver::createTextureExternalImageR(Handle th, + backend::SamplerType target, + backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) { mContext->textures.insert(construct_handle( th, *mContext, format, width, height, usage, (CVPixelBufferRef)image)); diff --git a/filament/backend/src/opengl/GLDescriptorSet.cpp b/filament/backend/src/opengl/GLDescriptorSet.cpp index 1584f6aff7..79c65d9a12 100644 --- a/filament/backend/src/opengl/GLDescriptorSet.cpp +++ b/filament/backend/src/opengl/GLDescriptorSet.cpp @@ -173,6 +173,7 @@ void GLDescriptorSet::update(OpenGLContext& gl, arg.target = t ? t->gl.target : 0; arg.id = t ? t->gl.id : 0; + arg.external = t ? t->gl.external : false; if constexpr (std::is_same_v || std::is_same_v) { if constexpr (std::is_same_v) { @@ -285,7 +286,7 @@ void GLDescriptorSet::bind( } else if constexpr (std::is_same_v) { GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); gl.bindSampler(unit, arg.sampler); if (UTILS_UNLIKELY(arg.ref)) { updateTextureView(gl, handleAllocator, unit, arg); @@ -296,7 +297,7 @@ void GLDescriptorSet::bind( } else if constexpr (std::is_same_v) { GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); gl.bindSampler(unit, arg.sampler); if (UTILS_UNLIKELY(arg.ref)) { updateTextureView(gl, handleAllocator, unit, arg); @@ -314,7 +315,7 @@ void GLDescriptorSet::bind( // in ES2 the sampler parameters need to be set on the texture itself GLuint const unit = p.getTextureUnit(set, binding); if (arg.target) { - gl.bindTexture(unit, arg.target, arg.id); + gl.bindTexture(unit, arg.target, arg.id, arg.external); SamplerParams const params = arg.params; glTexParameteri(arg.target, GL_TEXTURE_MIN_FILTER, (GLint)GLUtils::getTextureFilter(params.filterMin)); diff --git a/filament/backend/src/opengl/GLDescriptorSet.h b/filament/backend/src/opengl/GLDescriptorSet.h index 51ac2afd88..59b6b6ace5 100644 --- a/filament/backend/src/opengl/GLDescriptorSet.h +++ b/filament/backend/src/opengl/GLDescriptorSet.h @@ -111,7 +111,9 @@ private: // A sampler descriptor struct Sampler { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 GLuint sampler = 0; // 4 Handle ref; // 4 @@ -126,7 +128,9 @@ private: }; struct SamplerWithAnisotropyWorkaround { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 GLuint sampler = 0; // 4 Handle ref; // 4 @@ -143,7 +147,9 @@ private: // A sampler descriptor for ES2 struct SamplerGLES2 { - GLenum target = 0; // 4 + uint16_t target; // 2 (GLenum) + bool external = false; // 1 + bool reserved = false; // 1 GLuint id = 0; // 4 SamplerParams params{}; // 4 float anisotropy = 1.0f; // 4 diff --git a/filament/backend/src/opengl/GLTexture.h b/filament/backend/src/opengl/GLTexture.h index 5d721d3c21..26784d1564 100644 --- a/filament/backend/src/opengl/GLTexture.h +++ b/filament/backend/src/opengl/GLTexture.h @@ -35,7 +35,7 @@ struct GLTextureRef { GLTextureRef() = default; // view reference counter uint16_t count = 1; - // current per-view values of the texture (in GL we can only have a single View active at + // Current per-view values of the texture (in GL we can only have a single View active at // a time, and this tracks that state). It's used to avoid unnecessarily change state. int8_t baseLevel = 127; int8_t maxLevel = -1; @@ -50,7 +50,7 @@ struct GLTextureRef { struct GLTexture : public HwTexture { using HwTexture::HwTexture; struct GL { - GL() noexcept : imported(false), sidecarSamples(1), reserved1(0) {} + GL() noexcept : imported(false), external(false), sidecarSamples(1), reserved1(0) {} GLuint id = 0; // texture or renderbuffer id GLenum target = 0; GLenum internalFormat = 0; @@ -62,7 +62,8 @@ struct GLTexture : public HwTexture { int8_t maxLevel = -1; uint8_t reserved0 = 0; bool imported : 1; - uint8_t sidecarSamples : 4; + bool external : 1; + uint8_t sidecarSamples : 3; uint8_t reserved1 : 3; std::array swizzle{ TextureSwizzle::CHANNEL_0, diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 39ceb34678..4435425912 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -153,7 +153,7 @@ public: void pixelStore(GLenum, GLint) noexcept; inline void activeTexture(GLuint unit) noexcept; - inline void bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept; + inline void bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept; void unbindTexture(GLenum target, GLuint id) noexcept; void unbindTextureUnit(GLuint unit) noexcept; @@ -761,7 +761,9 @@ void OpenGLContext::bindBufferRange(GLenum target, GLuint index, GLuint buffer, #endif } -void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept { +void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept { + // another texture is bound to the same unit with a different target, + // unbind the texture from the current target update_state(state.textures.units[unit].target, target, [&]() { activeTexture(unit); glBindTexture(state.textures.units[unit].target, 0); @@ -769,7 +771,7 @@ void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexce update_state(state.textures.units[unit].id, texId, [&]() { activeTexture(unit); glBindTexture(target, texId); - }, target == GL_TEXTURE_EXTERNAL_OES); + }, external); } void OpenGLContext::useProgram(GLuint program) noexcept { diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 7ee4f5a3ab..0052c275a3 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -402,7 +402,7 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept { assert_invariant(t != nullptr); - mContext.bindTexture(unit, t->gl.target, t->gl.id); + mContext.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external); } bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept { @@ -1052,14 +1052,36 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle th, backend::TextureFormat format, - uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) { +void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType target, + TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) { DEBUG_MARKER() - createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage); - GLTexture* t = handle_cast(th); + usage |= TextureUsage::SAMPLEABLE; + usage &= ~TextureUsage::UPLOADABLE; + + auto& gl = mContext; + GLenum internalFormat = getInternalFormat(format); + if (UTILS_UNLIKELY(gl.isES2())) { + // on ES2, format and internal format must match + // FIXME: handle compressed texture format + internalFormat = textureFormatToFormatAndType(format).first; + } + assert_invariant(internalFormat); + + GLTexture* const t = construct(th, target, 1, 1, width, height, 1, format, usage); assert_invariant(t); - assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL); + + t->externalTexture = mPlatform.createExternalImageTexture(); + if (t->externalTexture) { + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + // internalFormat actually depends on the external image, but it doesn't matter + // because it's not used anywhere for anything important. + t->gl.internalFormat = internalFormat; + t->gl.baseLevel = 0; + t->gl.maxLevel = 0; + t->gl.external = true; // forces bindTexture() call (they're never cached) + } bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); if (mPlatform.setExternalImage(image, t->externalTexture)) { @@ -1092,6 +1114,7 @@ void OpenGLDriver::importTextureR(Handle th, intptr_t id, switch (target) { case SamplerType::SAMPLER_EXTERNAL: t->gl.target = GL_TEXTURE_EXTERNAL_OES; + t->gl.external = true; // forces bindTexture() call (they're never cached) break; case SamplerType::SAMPLER_2D: t->gl.target = GL_TEXTURE_2D; @@ -3503,7 +3526,7 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) { auto& gl = mContext; gl.bindVertexArray(nullptr); for (int unit = OpenGLContext::DUMMY_TEXTURE_BINDING; unit >= 0; unit--) { - gl.bindTexture(unit, GL_TEXTURE_2D, 0); + gl.bindTexture(unit, GL_TEXTURE_2D, 0, false); } gl.disable(GL_CULL_FACE); gl.depthFunc(GL_LESS); diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 38b8b9d504..9e6b628f02 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -715,14 +715,16 @@ void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept { bool PlatformEGL::setExternalImage(void* externalImage, UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { - if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - assert_invariant(texture->target == GL_TEXTURE_EXTERNAL_OES); + + // OES_EGL_image_external_essl3 must be present if the target is TEXTURE_EXTERNAL_OES + // GL_OES_EGL_image must be present if TEXTURE_2D is used + +#if defined(GL_OES_EGL_image) || defined(GL_OES_EGL_image_external_essl3) // the texture is guaranteed to be bound here. -#ifdef GL_OES_EGL_image - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, + glEGLImageTargetTexture2DOES(texture->target, static_cast(externalImage)); #endif - } + return true; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 3e7238c1e5..26d3064ba9 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -543,7 +543,8 @@ void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle th, backend::TextureFormat format, +void VulkanDriver::createTextureExternalImageR(Handle th, + backend::SamplerType target, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) { FVK_SYSTRACE_SCOPE(); diff --git a/filament/backend/test/test_RenderExternalImage.cpp b/filament/backend/test/test_RenderExternalImage.cpp index 414e9c414d..643545a2be 100644 --- a/filament/backend/test/test_RenderExternalImage.cpp +++ b/filament/backend/test/test_RenderExternalImage.cpp @@ -227,7 +227,8 @@ TEST_F(BackendTest, RenderExternalImage) { api.setupExternalImage(pixBuffer); backend::Handle texture = - api.createTextureExternalImage(TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer); + api.createTextureExternalImage(SamplerType::SAMPLER_EXTERNAL, + TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer); // We're now free to release the buffer. CVBufferRelease(pixBuffer); diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index b351c42943..6813b13e73 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -261,6 +261,18 @@ public: */ Builder& import(intptr_t id) noexcept; + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * + * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. + * + * @return + */ + Builder& external() noexcept; + private: friend class FTexture; }; @@ -395,7 +407,7 @@ public: /** - * Specify the external image to associate with this Texture. Typically the external + * Specify the external image to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. * There are many restrictions when using an external image as a texture, such as: * - only the level of detail (lod) 0 can be specified @@ -420,7 +432,7 @@ public: void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; /** - * Specify the external image and plane to associate with this Texture. Typically the external + * Specify the external image and plane to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. When using this method, the * external image must be a planar type (such as a YUV camera frame). The plane parameter * selects which image plane is bound to this texture. diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index 176907345b..cff6d7e42a 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -81,6 +81,7 @@ struct Texture::BuilderDetails { Usage mUsage = Usage::NONE; bool mHasBlitSrc = false; bool mTextureIsSwizzled = false; + bool mExternal = false; std::array mSwizzle = { Swizzle::CHANNEL_0, Swizzle::CHANNEL_1, Swizzle::CHANNEL_2, Swizzle::CHANNEL_3 }; @@ -136,6 +137,11 @@ Texture::Builder& Texture::Builder::import(intptr_t id) noexcept { return *this; } +Texture::Builder& Texture::Builder::external() noexcept { + mImpl->mExternal = true; + return *this; +} + Texture::Builder& Texture::Builder::swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept { mImpl->mTextureIsSwizzled = true; mImpl->mSwizzle = { r, g, b, a }; @@ -154,6 +160,11 @@ Texture* Texture::Builder::build(Engine& engine) { (isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory) << "Texture is PROTECTED but protected textures are not supported"; + // SAMPLER_EXTERNAL implies imported. + if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) { + mImpl->mExternal = true; + } + uint8_t maxLevelCount; switch (mImpl->mTarget) { case SamplerType::SAMPLER_2D: @@ -174,7 +185,7 @@ Texture* Texture::Builder::build(Engine& engine) { mImpl->mUsage = TextureUsage::DEFAULT; if (mImpl->mLevels > 1 && (mImpl->mWidth > 1 || mImpl->mHeight > 1) && - mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) { + !mImpl->mExternal) { const bool formatMipmappable = downcast(engine).getDriverApi().isTextureFormatMipmappable(mImpl->mFormat); if (formatMipmappable) { @@ -243,9 +254,10 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) { mSwizzle = builder->mSwizzle; mTextureIsSwizzled = builder->mTextureIsSwizzled; mHasBlitSrc = builder->mHasBlitSrc; + mExternal = builder->mExternal; bool const isImported = builder->mImportedId != 0; - if (mTarget == SamplerType::SAMPLER_EXTERNAL && !isImported) { + if (mExternal && !isImported) { // mHandle and mHandleForSampling will be created in setExternalImage() // If this Texture is used for sampling before setExternalImage() is called, // we'll lazily create a 1x1 placeholder texture. @@ -318,8 +330,8 @@ void FTexture::setImage(FEngine& engine, size_t level, << "level=" << unsigned(level) << " is >= to levelCount=" << unsigned(mLevelCount) << "."; - FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL) - << "Texture SamplerType::SAMPLER_EXTERNAL not supported for this operation."; + FILAMENT_CHECK_PRECONDITION(!mExternal) + << "External Texture not supported for this operation."; FILAMENT_CHECK_PRECONDITION(mSampleCount <= 1) << "Operation not supported with multisample (" << unsigned(mSampleCount) << ") texture."; @@ -454,15 +466,14 @@ void FTexture::setImage(FEngine& engine, size_t level, } void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + // The call to setupExternalImage is synchronous, and allows the driver to take ownership of the // external image on this thread, if necessary. auto& api = engine.getDriverApi(); api.setupExternalImage(image); - auto texture = api.createTextureExternalImage(mFormat, mWidth, mHeight, mUsage, image); + auto texture = api.createTextureExternalImage(mTarget, mFormat, mWidth, mHeight, mUsage, image); if (mTextureIsSwizzled) { auto const& s = mSwizzle; @@ -475,9 +486,8 @@ void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { } void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + // The call to setupExternalImage is synchronous, and allows the driver to take ownership of // the external image on this thread, if necessary. auto& api = engine.getDriverApi(); @@ -497,9 +507,7 @@ void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noex } void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept { - if (mTarget != Sampler::SAMPLER_EXTERNAL) { - return; - } + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; auto& api = engine.getDriverApi(); auto texture = api.createTexture( @@ -524,7 +532,7 @@ void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept { } void FTexture::generateMipmaps(FEngine& engine) const noexcept { - FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL) + FILAMENT_CHECK_PRECONDITION(!mExternal) << "External Textures are not mipmappable."; FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_3D) @@ -544,12 +552,11 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept { } bool FTexture::textureHandleCanMutate() const noexcept { - return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) || - mTarget == SamplerType::SAMPLER_EXTERNAL; + return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) || mExternal; } void FTexture::updateLodRange(uint8_t baseLevel, uint8_t levelCount) noexcept { - assert_invariant(mTarget != SamplerType::SAMPLER_EXTERNAL); + assert_invariant(!mExternal); if (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) { auto& range = mLodRange; uint8_t const last = int8_t(baseLevel + levelCount); @@ -601,7 +608,7 @@ backend::Handle FTexture::createPlaceholderTexture( } backend::Handle FTexture::getHwHandleForSampling() const noexcept { - if (UTILS_UNLIKELY(mTarget == SamplerType::SAMPLER_EXTERNAL && !mHandleForSampling)) { + if (UTILS_UNLIKELY(mExternal && !mHandleForSampling)) { return setHandleForSampling(createPlaceholderTexture(*mDriver)); } auto const& range = mLodRange; @@ -610,9 +617,10 @@ backend::Handle FTexture::getHwHandleForSampling() const noe if (UTILS_UNLIKELY(lodRangeChanged)) { activeRange = range; if (range.empty() || hasAllLods(range)) { - setHandleForSampling(mHandle); + std::ignore = setHandleForSampling(mHandle); } else { - setHandleForSampling(mDriver->createTextureView(mHandle, range.first, range.size())); + std::ignore = setHandleForSampling(mDriver->createTextureView( + mHandle, range.first, range.size())); } } return mHandleForSampling; diff --git a/filament/src/details/Texture.h b/filament/src/details/Texture.h index 6bf04dae4a..2131988c84 100644 --- a/filament/src/details/Texture.h +++ b/filament/src/details/Texture.h @@ -173,7 +173,8 @@ private: // Indicates whether the user has set the TextureUsage::BLIT_SRC usage. This will be used to // temporarily validate whether this texture can be used for readPixels. bool mHasBlitSrc = false; - // there is 5 bytes of padding here + bool mExternal = false; + // there is 4 bytes of padding here FStream* mStream = nullptr; // only needed for streaming textures }; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index c45c50b35b..1ca1b97c93 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1489,6 +1489,8 @@ class_("Texture$Builder") return &builder->sampler(target); }) .BUILDER_FUNCTION("format", TexBuilder, (TexBuilder* builder, Texture::InternalFormat fmt), { return &builder->format(fmt); }) + .BUILDER_FUNCTION("external", TexBuilder, (TexBuilder* builder), { + return &builder->external(); }) // This takes a bitfield that can be composed by or'ing constants. // - JS clients should use the value member, as in: "Texture$Usage.SAMPLEABLE.value". From a003d3721d1b299d5d973605e518d773b84c1fdb Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Tue, 7 Jan 2025 10:11:12 -0800 Subject: [PATCH 08/11] matdbg: enable source formatting (#8338) We use clang-format to format the shader files. Since we assume clang is necessary for compilation, installing clang-format should not be too much of an overhead in terms of adding dependency. Currently, we only support posix systems (macOS, linux). --- libs/matdbg/CMakeLists.txt | 2 + libs/matdbg/src/ApiHandler.cpp | 31 +++++------ libs/matdbg/src/ApiHandler.h | 4 ++ libs/matdbg/src/SourceFormatter.cpp | 80 +++++++++++++++++++++++++++++ libs/matdbg/src/SourceFormatter.h | 37 +++++++++++++ 5 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 libs/matdbg/src/SourceFormatter.cpp create mode 100644 libs/matdbg/src/SourceFormatter.h diff --git a/libs/matdbg/CMakeLists.txt b/libs/matdbg/CMakeLists.txt index e580585480..566aec3fd3 100644 --- a/libs/matdbg/CMakeLists.txt +++ b/libs/matdbg/CMakeLists.txt @@ -31,6 +31,8 @@ set(SRCS src/ShaderReplacer.cpp src/ShaderExtractor.cpp src/ShaderInfo.cpp + src/SourceFormatter.cpp + src/SourceFormatter.h src/TextWriter.cpp ) diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index 82e27fa53a..c9ef42c0ee 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -43,19 +43,6 @@ namespace { auto const& kSuccessHeader = DebugServer::kSuccessHeader; auto const& kErrorHeader = DebugServer::kErrorHeader; -void spirvToAsm(struct mg_connection* conn, uint32_t const* spirv, size_t size) { - auto spirvDisassembly = ShaderExtractor::spirvToText(spirv, size / 4); - mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size()); -} - -void spirvToGlsl(ShaderModel shaderModel, struct mg_connection* conn, uint32_t const* spirv, - size_t size) { - auto glsl = ShaderExtractor::spirvToGLSL(shaderModel, spirv, size / 4); - mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_printf(conn, glsl.c_str(), glsl.size()); -} - } // anonymous using filaflat::ChunkContainer; @@ -145,8 +132,10 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, filaflat::ShaderContent content; extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); + std::string const shader = mFormatter.format((char const*) content.data()); mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, content.data(), content.size() - 1); + mg_write(conn, shader.c_str(), shader.size()); + return true; } @@ -171,12 +160,19 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); if (language == spirv) { - spirvToAsm(conn, (uint32_t const*) content.data(), content.size()); + auto spirvDisassembly = ShaderExtractor::spirvToText((uint32_t const*) content.data(), + content.size() / 4); + mg_printf(conn, kSuccessHeader.data(), "application/txt"); + mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size()); return true; } if (language == glsl) { - spirvToGlsl(item.shaderModel, conn, (uint32_t const*) content.data(), content.size()); + auto glsl = ShaderExtractor::spirvToGLSL(item.shaderModel, + (uint32_t const*) content.data(), content.size() / 4); + std::string const shader = mFormatter.format((char const*) glsl.c_str()); + mg_printf(conn, kSuccessHeader.data(), "application/txt"); + mg_printf(conn, shader.c_str(), shader.size()); return true; } @@ -204,8 +200,9 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); if (language == msl) { + std::string const shader = mFormatter.format((char const*) content.data()); mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, content.data(), content.size() - 1); + mg_write(conn, shader.c_str(), shader.size()); return true; } diff --git a/libs/matdbg/src/ApiHandler.h b/libs/matdbg/src/ApiHandler.h index 81aaa7c734..353326a7dc 100644 --- a/libs/matdbg/src/ApiHandler.h +++ b/libs/matdbg/src/ApiHandler.h @@ -17,6 +17,8 @@ #ifndef MATDBG_APIHANDLER_H #define MATDBG_APIHANDLER_H +#include "SourceFormatter.h" + #include #include #include @@ -63,6 +65,8 @@ private: // will always block until statusMaterialId is updated again. The client is expected to keep // calling /api/status (a constant "pull" to simulate a push). std::atomic mCurrentStatus = 0; + + SourceFormatter mFormatter; }; } // filament::matdbg diff --git a/libs/matdbg/src/SourceFormatter.cpp b/libs/matdbg/src/SourceFormatter.cpp new file mode 100644 index 0000000000..c068a34f4b --- /dev/null +++ b/libs/matdbg/src/SourceFormatter.cpp @@ -0,0 +1,80 @@ +/* + * 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 "SourceFormatter.h" + +#include + +#include +#include + +namespace filament::matdbg { + +#if defined(__linux__) || defined(__APPLE__) +std::string SourceFormatter::format(char const* source) { + std::string const TMP_FILENAME = "/tmp/matdbg-tmp-src.cpp"; + + std::string original(source); + FILE* fp; + fp = fopen(TMP_FILENAME.c_str(), "w"); + if (!fp) { + return original; + } + fputs(original.c_str(), fp); + fflush(fp); + pclose(fp); + + std::string const CLANG_FORMAT_OPTIONS = + "-style='{" + "BasedOnStyle: Google, " + "IndentWidth: 4, " + "MaxEmptyLinesToKeep: 2" + "}'"; + + fp = popen(("clang-format " + CLANG_FORMAT_OPTIONS + "< " + TMP_FILENAME).c_str(), "r"); + + if (!fp) { + std::call_once(mClangWarningFlag, []() { + utils::slog.w << "[matdbg] unable to run clang-format to format shader file. " + << "Please make sure it's installed."; + }); + return original; + } + + char output[1024]; + std::stringstream outStream; + while (fgets(output, 1024, fp) != NULL) { + outStream << output; + } + + int status = pclose(fp); + if (WEXITSTATUS(status)) { + utils::slog.w << "[matdbg] clang-format failed with code=" << WEXITSTATUS(status) + << utils::io::endl; + } + return outStream.str(); +} +#else +std::string SourceFormatter::format(char const* source) { + std::call_once(mClangWarningFlag, []() { + utils::slog.w <<"[matdbg]: source formatting is not available on this platform" << + utils::io::endl; + }); + return ""; +} +#endif + +} // filament::matdbg diff --git a/libs/matdbg/src/SourceFormatter.h b/libs/matdbg/src/SourceFormatter.h new file mode 100644 index 0000000000..5793474d71 --- /dev/null +++ b/libs/matdbg/src/SourceFormatter.h @@ -0,0 +1,37 @@ +/* + * 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 MATDBG_SOURCE_FORMATTER_H +#define MATDBG_SOURCE_FORMATTER_H + +#include + +namespace filament::matdbg { + +class SourceFormatter { +public: + SourceFormatter() = default; + ~SourceFormatter() = default; + std::string format(char const* source); + +private: + + std::once_flag mClangWarningFlag; +}; + +} // filament::matdbg + +#endif // MATDBG_SOURCE_FORMATTER_H From f0b9a30bc1a0ad7f7169ebe06ced1926c792eead Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Tue, 7 Jan 2025 11:42:17 -0800 Subject: [PATCH 09/11] matdbg: add option to hide inactive materials and variants (#8339) The option will persist beyond user sessions through localStorage. --- libs/matdbg/web/app.js | 98 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index cccec2b1b6..325d47487f 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -452,6 +452,7 @@ class AdvancedOptions extends LitElement { static get properties() { return { currentBackend: {type: String, attribute: 'current-backend'}, + hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'}, availableBackends: {type: Array, state: true}, }; } @@ -470,6 +471,9 @@ class AdvancedOptions extends LitElement { justify-content: center; align-items: flex-start; } + .borderless { + border: 1px solid rgba(0,0,0,0); + } label { display: flex; flex-direction: row; @@ -486,6 +490,35 @@ class AdvancedOptions extends LitElement { .option-heading { margin-bottom: 5px; } + + /* Below is a custom checkbox */ + input[type="checkbox"] { + -webkit-appearance: none; + appearance: none; + background-color: var(--form-background); + margin-right: 5px; + font: inherit; + width: 1.15em; + height: 1.15em; + border: 0.15em solid ${unsafeCSS(UNSELECTED_COLOR)}; + border-radius: 0.15em; + display: grid; + place-content: center; + } + input[type="checkbox"]::before { + content: ""; + width: 0.65em; + height: 0.65em; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); + transform: scale(0); + transform-origin: bottom left; + box-shadow: inset 1em 1em var(--form-control-color); + /* Windows High Contrast Mode */ + background-color: ${unsafeCSS(FOREGROUND_COLOR)}; + } + input[type="checkbox"]:checked::before { + transform: scale(1); + } `; } @@ -536,6 +569,25 @@ class AdvancedOptions extends LitElement { `; } + _hideInactiveVariantsOption() { + const onChange = (ev) => { + this.dispatchEvent( + new CustomEvent( + 'option-hide-inactive-variants', + {detail: null, bubbles: true, composed: true})); + } + return html` +
+ +
+ + Hide Inactive Variants +
+
+ `; + } + constructor() { super(); this.availableBackends = []; @@ -544,6 +596,7 @@ class AdvancedOptions extends LitElement { render() { return html` + ${this._hideInactiveVariantsOption() ?? nothing} ${this._backendOption() ?? nothing} `; @@ -613,11 +666,11 @@ class MaterialSidePanel extends LitElement { currentShaderIndex: {type: Number, attribute: 'current-shader-index'}, currentBackend: {type: String, attribute: 'current-backend'}, currentLanguage: {type: String, attribute: 'current-language'}, + hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'}, database: {type: Object, state: true}, materials: {type: Array, state: true}, activeShaders: {type: Object, state: true}, - variants: {type: Array, state: true}, } } @@ -747,6 +800,7 @@ class MaterialSidePanel extends LitElement { if (b.active && !a.active) return 1; return 0; }) + .filter((variant) => (!this.hideInactiveVariants || variant.shader.active)) .map((variant) => { let divClass = 'material_variant_language'; const shaderIndex = +variant.shader.index; @@ -778,7 +832,13 @@ class MaterialSidePanel extends LitElement { render() { const sections = (title, domain) => { - const mats = this.materials.filter((m) => m.domain == domain).map((mat) => { + const mats = this.materials + .filter((m) => m.domain == domain) + .filter((mat) => { + const material = this.database[mat.matid]; + return !this.hideInactiveVariants || material.active; + }) + .map((mat) => { const material = this.database[mat.matid]; const onClick = this._handleMaterialClick.bind(this, mat.matid); let divClass = 'material_variant_language'; @@ -806,15 +866,13 @@ class MaterialSidePanel extends LitElement { } return null; }; - let advancedOptions = null; - // Currently we only have one advanced option and it's only for when we're in matinfo - if (_isMatInfoMode(this.database)) { - advancedOptions = - (() => html` - - `)(); - } + const advancedOptions = + (() => html` + + `)(); return html` @@ -874,6 +932,12 @@ class MatdbgViewer extends LitElement { let materials = await fetchMaterials(); this.database = materials; + + // This is the user preferences stored in localStorage + let hideInactiveVariantsVal = localStorage.getItem('option-hide-inactive-variants'); + if (hideInactiveVariantsVal != null) { + this.hideInactiveVariants = hideInactiveVariantsVal == 'true'; + } } _getShader() { @@ -907,6 +971,7 @@ class MatdbgViewer extends LitElement { this.currentMaterial = null; this.currentLanguage = null; this.currentBackend = null; + this.hideInactiveVariants = false; this.init(); this.addEventListener('select-material', @@ -957,6 +1022,12 @@ class MatdbgViewer extends LitElement { } ); + this.addEventListener('option-hide-inactive-variants', + (ev) => { + this.hideInactiveVariants = !this.hideInactiveVariants; + localStorage.setItem('option-hide-inactive-variants', "" + this.hideInactiveVariants); + } + ); addEventListener('resize', this._onResize.bind(this)); } @@ -972,6 +1043,8 @@ class MatdbgViewer extends LitElement { currentBackend: {type: String, state: true}, codeViewerExpectedWidth: {type: Number, state: true}, codeViewerExpectedHeight: {type: Number, state: true}, + + hideInactiveVariants: {type: Boolean, state: true}, } } @@ -1085,7 +1158,8 @@ class MatdbgViewer extends LitElement { current-language="${this.currentLanguage}" current-shader-index="${this.currentShaderIndex}" current-material="${this.currentMaterial}" - current-backend="${this.currentBackend}" > + current-backend="${this.currentBackend}" + ?hide-inactive-variants="${this.hideInactiveVariants}" > Date: Wed, 8 Jan 2025 13:11:39 -0800 Subject: [PATCH 10/11] Rename IOS define to FILAMENT_IOS (#8340) --- filament/backend/src/PlatformFactory.cpp | 6 +++--- filament/backend/src/metal/MetalBuffer.h | 2 +- filament/backend/src/metal/MetalDriver.mm | 12 ++++++------ filament/backend/src/metal/MetalEnums.h | 4 ++-- filament/backend/src/metal/MetalHandles.mm | 8 ++++---- filament/backend/src/metal/MetalPlatform.mm | 2 +- filament/backend/src/metal/MetalState.mm | 2 +- filament/backend/src/noop/NoopDriver.cpp | 2 +- filament/backend/src/opengl/OpenGLContext.cpp | 12 ++++++------ filament/backend/src/opengl/OpenGLContext.h | 2 +- filament/backend/src/opengl/OpenGLDriver.cpp | 4 ++-- filament/backend/src/opengl/gl_headers.h | 8 ++++---- filament/backend/src/vulkan/VulkanDriver.cpp | 2 +- .../src/vulkan/platform/VulkanPlatformApple.mm | 6 +++--- filament/backend/test/BackendTest.cpp | 4 ++-- filament/backend/test/test_Blit.cpp | 4 ++-- filament/backend/test/test_FeedbackLoops.cpp | 4 ++-- filament/backend/test/test_ReadPixels.cpp | 4 ++-- libs/bluevk/include/bluevk/BlueVK.h | 2 +- libs/filamentapp/src/FilamentApp.cpp | 2 +- libs/gltfio/src/AssetLoader.cpp | 2 +- libs/gltfio/src/FFilamentAsset.h | 2 +- samples/gltf_viewer.cpp | 2 +- third_party/clang/iOS.cmake | 2 +- 24 files changed, 50 insertions(+), 50 deletions(-) diff --git a/filament/backend/src/PlatformFactory.cpp b/filament/backend/src/PlatformFactory.cpp index 86be6d231e..cccd9439c3 100644 --- a/filament/backend/src/PlatformFactory.cpp +++ b/filament/backend/src/PlatformFactory.cpp @@ -24,7 +24,7 @@ #if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) #include "backend/platforms/PlatformEGLAndroid.h" #endif -#elif defined(IOS) +#elif defined(FILAMENT_IOS) #if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) #include "backend/platforms/PlatformCocoaTouchGL.h" #endif @@ -88,7 +88,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept { *backend = Backend::OPENGL; #elif defined(__ANDROID__) *backend = Backend::OPENGL; -#elif defined(IOS) || defined(__APPLE__) +#elif defined(FILAMENT_IOS) || defined(__APPLE__) *backend = Backend::METAL; #elif defined(FILAMENT_DRIVER_SUPPORTS_VULKAN) *backend = Backend::VULKAN; @@ -119,7 +119,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept { return nullptr; #elif defined(__ANDROID__) return new PlatformEGLAndroid(); - #elif defined(IOS) + #elif defined(FILAMENT_IOS) return new PlatformCocoaTouchGL(); #elif defined(__APPLE__) return new PlatformCocoaGL(); diff --git a/filament/backend/src/metal/MetalBuffer.h b/filament/backend/src/metal/MetalBuffer.h index f6fa90c199..ec724a9f0b 100644 --- a/filament/backend/src/metal/MetalBuffer.h +++ b/filament/backend/src/metal/MetalBuffer.h @@ -250,7 +250,7 @@ public: // In practice, MetalRingBuffer is used for argument buffers, which are kept in the constant // address space. Constant buffers have specific alignment requirements when specifying an // offset. -#if defined(IOS) +#if defined(FILAMENT_IOS) #if TARGET_OS_SIMULATOR // The iOS simulator has differing alignment requirements. static constexpr auto METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT = 256; diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 38b9b6e0d3..46dcb3716e 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -909,7 +909,7 @@ void MetalDriver::terminate() { } ShaderModel MetalDriver::getShaderModel() const noexcept { -#if defined(IOS) +#if defined(FILAMENT_IOS) return ShaderModel::MOBILE; #else return ShaderModel::DESKTOP; @@ -983,7 +983,7 @@ bool MetalDriver::isTextureFormatMipmappable(TextureFormat format) { case MTLPixelFormatRGBA16Float: return true; -#if !defined(IOS) +#if !defined(FILAMENT_IOS) // Mipmappable only on desktop: case MTLPixelFormatR32Float: case MTLPixelFormatRG32Float: @@ -991,7 +991,7 @@ bool MetalDriver::isTextureFormatMipmappable(TextureFormat format) { return true; #endif -#if defined(IOS) +#if defined(FILAMENT_IOS) // Mipmappable only on iOS: case MTLPixelFormatRGB9E5Float: return true; @@ -1364,7 +1364,7 @@ void MetalDriver::startCapture(int) { if (@available(iOS 13, *)) { MTLCaptureDescriptor* descriptor = [MTLCaptureDescriptor new]; descriptor.captureObject = mContext->device; -#if defined(IOS) +#if defined(FILAMENT_IOS) descriptor.destination = MTLCaptureDestinationDeveloperTools; #else descriptor.destination = MTLCaptureDestinationGPUTraceDocument; @@ -1428,7 +1428,7 @@ void MetalDriver::readPixels(Handle src, uint32_t x, uint32_t y, width:srcTextureSize.width height:srcTextureSize.height mipmapped:NO]; -#if defined(IOS) +#if defined(FILAMENT_IOS) textureDescriptor.storageMode = MTLStorageModeShared; #else textureDescriptor.storageMode = MTLStorageModeManaged; @@ -1447,7 +1447,7 @@ void MetalDriver::readPixels(Handle src, uint32_t x, uint32_t y, mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "readPixels blit"); -#if !defined(IOS) +#if !defined(FILAMENT_IOS) // Managed textures on macOS require explicit synchronization between GPU / CPU. id blitEncoder = [getPendingCommandBuffer(mContext) blitCommandEncoder]; [blitEncoder synchronizeResource:readPixelsTexture]; diff --git a/filament/backend/src/metal/MetalEnums.h b/filament/backend/src/metal/MetalEnums.h index 10899baf95..5a2038ed10 100644 --- a/filament/backend/src/metal/MetalEnums.h +++ b/filament/backend/src/metal/MetalEnums.h @@ -196,7 +196,7 @@ inline MTLPixelFormat getMetalFormatLinear(MTLPixelFormat format) { case MTLPixelFormatRG8Unorm_sRGB: return MTLPixelFormatRG8Unorm; case MTLPixelFormatRGBA8Unorm_sRGB: return MTLPixelFormatRGBA8Unorm; case MTLPixelFormatBGRA8Unorm_sRGB: return MTLPixelFormatBGRA8Unorm; -#if !defined(IOS) +#if !defined(FILAMENT_IOS) case MTLPixelFormatBC1_RGBA_sRGB: return MTLPixelFormatBC1_RGBA; case MTLPixelFormatBC2_RGBA_sRGB: return MTLPixelFormatBC2_RGBA; case MTLPixelFormatBC3_RGBA_sRGB: return MTLPixelFormatBC3_RGBA; @@ -268,7 +268,7 @@ constexpr inline bool isMetalFormatStencil(MTLPixelFormat format) { case MTLPixelFormatStencil8: case MTLPixelFormatDepth32Float_Stencil8: case MTLPixelFormatX32_Stencil8: -#if !defined(IOS) +#if !defined(FILAMENT_IOS) case MTLPixelFormatDepth24Unorm_Stencil8: case MTLPixelFormatX24_Stencil8: #endif diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index 60cf484c86..fc12fe0a9a 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -157,7 +157,7 @@ id MetalSwapChain::acquireDrawable() { textureDescriptor.height = headlessHeight; // Specify MTLTextureUsageShaderRead so the headless surface can be blitted from. textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; -#if defined(IOS) +#if defined(FILAMENT_IOS) textureDescriptor.storageMode = MTLStorageModeShared; #else textureDescriptor.storageMode = MTLStorageModeManaged; @@ -520,7 +520,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le const BOOL mipmapped = levels > 1; const BOOL multisampled = samples > 1; -#if defined(IOS) +#if defined(FILAMENT_IOS) const BOOL textureArray = target == SamplerType::SAMPLER_2D_ARRAY; FILAMENT_CHECK_PRECONDITION(!textureArray || !multisampled) << "iOS does not support multisampled texture arrays."; @@ -533,7 +533,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le switch (target) { case SamplerType::SAMPLER_2D: return MTLTextureType2DMultisample; -#if !defined(IOS) +#if !defined(FILAMENT_IOS) case SamplerType::SAMPLER_2D_ARRAY: return MTLTextureType2DMultisampleArray; #endif @@ -856,7 +856,7 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region descriptor.height = region.size.height; descriptor.depth = region.size.depth; -#if defined(IOS) +#if defined(FILAMENT_IOS) descriptor.storageMode = MTLStorageModeShared; #else descriptor.storageMode = MTLStorageModeManaged; diff --git a/filament/backend/src/metal/MetalPlatform.mm b/filament/backend/src/metal/MetalPlatform.mm index 31ce2a8070..4979e602ba 100644 --- a/filament/backend/src/metal/MetalPlatform.mm +++ b/filament/backend/src/metal/MetalPlatform.mm @@ -37,7 +37,7 @@ Driver* MetalPlatform::createDriver(void* /*sharedContext*/, const Platform::Dri id MetalPlatform::createDevice() noexcept { id result; -#if !defined(IOS) +#if !defined(FILAMENT_IOS) const bool forceIntegrated = NSProcessInfo.processInfo.environment[@"FILAMENT_FORCE_INTEGRATED_GPU"] != nil; if (forceIntegrated) { diff --git a/filament/backend/src/metal/MetalState.mm b/filament/backend/src/metal/MetalState.mm index 065e2b62cc..c790e03c30 100644 --- a/filament/backend/src/metal/MetalState.mm +++ b/filament/backend/src/metal/MetalState.mm @@ -150,7 +150,7 @@ id SamplerStateCreator::operator()(id device, MTLCompareFunctionNever : getCompareFunction(params.compareFunc); samplerDescriptor.supportArgumentBuffers = YES; -#if defined(IOS) +#if defined(FILAMENT_IOS) // Older Apple devices (and the simulator) don't support setting a comparison function in // MTLSamplerDescriptor. // In practice, this means shadows are not supported when running in the simulator. diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index 4f26222dc3..af3ad70fbb 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -32,7 +32,7 @@ Dispatcher NoopDriver::getDispatcher() const noexcept { } ShaderModel NoopDriver::getShaderModel() const noexcept { -#if defined(__ANDROID__) || defined(IOS) || defined(__EMSCRIPTEN__) +#if defined(__ANDROID__) || defined(FILAMENT_IOS) || defined(__EMSCRIPTEN__) return ShaderModel::MOBILE; #else return ShaderModel::DESKTOP; diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index d664e9e89a..f652d92659 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -408,7 +408,7 @@ void OpenGLContext::initProcs(Procs* procs, procs->maxShaderCompilerThreadsKHR = +[](GLuint) {}; #ifdef BACKEND_OPENGL_VERSION_GLES -# ifndef IOS // IOS is guaranteed to have ES3.x +# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x # ifndef __EMSCRIPTEN__ if (UTILS_UNLIKELY(major == 2)) { // Runtime OpenGL version is ES 2.x @@ -438,7 +438,7 @@ void OpenGLContext::initProcs(Procs* procs, procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsKHR; } # endif // __EMSCRIPTEN__ -# endif // IOS +# endif // FILAMENT_IOS #else procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsARB; #endif @@ -576,14 +576,14 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts, } #ifdef BACKEND_OPENGL_VERSION_GLES -# ifndef IOS // IOS is guaranteed to have ES3.x +# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x if (UTILS_UNLIKELY(major == 2)) { if (UTILS_UNLIKELY(!exts.OES_vertex_array_object)) { // we activate this workaround path, which does the reset of array buffer bugs->vao_doesnt_store_element_array_buffer_binding = true; } } -# endif // IOS +# endif // FILAMENT_IOS #else // feedback loops are allowed on GL desktop as long as writes are disabled bugs->allow_read_only_ancillary_feedback_loop = true; @@ -622,7 +622,7 @@ FeatureLevel OpenGLContext::resolveFeatureLevel(GLint major, GLint minor, } } } -# ifndef IOS // IOS is guaranteed to have ES3.x +# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x else if (UTILS_UNLIKELY(major == 2)) { // Runtime OpenGL version is ES 2.x // note: mandatory extensions (all supported by Mali-400 and Adreno 304) @@ -634,7 +634,7 @@ FeatureLevel OpenGLContext::resolveFeatureLevel(GLint major, GLint minor, // OES_texture_npot featureLevel = FeatureLevel::FEATURE_LEVEL_0; } -# endif // IOS +# endif // FILAMENT_IOS #else assert_invariant(gets.max_texture_image_units >= 16); assert_invariant(gets.max_combined_texture_image_units >= 32); diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 4435425912..72e3f8f2b1 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -131,7 +131,7 @@ public: } inline bool isES2() const noexcept { -#if defined(BACKEND_OPENGL_VERSION_GLES) && !defined(IOS) +#if defined(BACKEND_OPENGL_VERSION_GLES) && !defined(FILAMENT_IOS) # ifndef BACKEND_OPENGL_LEVEL_GLES30 return true; # else diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 0052c275a3..736fa0d676 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -1381,13 +1381,13 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo, #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 // TODO: support multiview for iOS and WebGL -#if !defined(__EMSCRIPTEN__) && !defined(IOS) +#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS) if (layerCount > 1) { // if layerCount > 1, it means we use the multiview extension. glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment, t->gl.id, 0, binfo.layer, layerCount); } else -#endif // !defined(__EMSCRIPTEN__) && !defined(IOS) +#endif // !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS) { // GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, diff --git a/filament/backend/src/opengl/gl_headers.h b/filament/backend/src/opengl/gl_headers.h index 04ad63ff6a..636bdb4824 100644 --- a/filament/backend/src/opengl/gl_headers.h +++ b/filament/backend/src/opengl/gl_headers.h @@ -56,7 +56,7 @@ # define FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 #endif -#elif defined(IOS) +#elif defined(FILAMENT_IOS) #define GLES_SILENCE_DEPRECATION @@ -81,7 +81,7 @@ #if defined(GL_VERSION_4_5) #elif defined(GL_ES_VERSION_3_1) #elif defined(GL_ES_VERSION_3_0) -# if !defined(IOS) && !defined(__EMSCRIPTEN__) +# if !defined(FILAMENT_IOS) && !defined(__EMSCRIPTEN__) # error "GLES 3.0 headers only supported on iOS and WebGL2" # endif #elif defined(GL_ES_VERSION_2_0) @@ -98,7 +98,7 @@ #if defined(GL_ES_VERSION_2_0) // this basically means all versions of GLES -#if defined(IOS) +#if defined(FILAMENT_IOS) // iOS headers only provide prototypes, nothing to do. @@ -271,7 +271,7 @@ void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void *d #endif #ifdef GL_ES_VERSION_2_0 -# ifndef IOS +# ifndef FILAMENT_IOS # ifndef GL_OES_vertex_array_object # error "Headers with GL_OES_vertex_array_object are mandatory unless on iOS" # endif diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 26d3064ba9..520ea22b78 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -288,7 +288,7 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont } ShaderModel VulkanDriver::getShaderModel() const noexcept { -#if defined(__ANDROID__) || defined(IOS) +#if defined(__ANDROID__) || defined(FILAMENT_IOS) return ShaderModel::MOBILE; #else return ShaderModel::DESKTOP; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm index 6504ae3a7c..6aa18749d3 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm +++ b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm @@ -32,7 +32,7 @@ #ifndef VK_MVK_macos_surface #error VK_MVK_macos_surface is not defined #endif -#elif defined(IOS) +#elif defined(FILAMENT_IOS) // Metal is not available when building for the iOS simulator on Desktop. #define METAL_AVAILABLE __has_include() #if METAL_AVAILABLE @@ -56,7 +56,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() { ExtensionSet const ret = { #if defined(__APPLE__) VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface - #elif defined(IOS) && defined(METAL_AVAILABLE) + #elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE) VK_MVK_IOS_SURFACE_EXTENSION_NAME, #endif }; @@ -90,7 +90,7 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin VkResult result = vkCreateMacOSSurfaceMVK((VkInstance) instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateMacOSSurfaceMVK error."; - #elif defined(IOS) && defined(METAL_AVAILABLE) + #elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE) CAMetalLayer* metalLayer = (CAMetalLayer*) nativeWindow; // Create the VkSurface. FILAMENT_CHECK_POSTCONDITION(vkCreateIOSSurfaceMVK) diff --git a/filament/backend/test/BackendTest.cpp b/filament/backend/test/BackendTest.cpp index 6eede04f00..ff4e8bb1ca 100644 --- a/filament/backend/test/BackendTest.cpp +++ b/filament/backend/test/BackendTest.cpp @@ -33,7 +33,7 @@ static constexpr size_t CONFIG_COMMAND_BUFFERS_SIZE = 3 * CONFIG_MIN_COMMAND using namespace filament; using namespace filament::backend; -#ifndef IOS +#ifndef FILAMENT_IOS #include #include @@ -177,7 +177,7 @@ void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, si // Export a screenshot, if requested. if (c->exportScreenshot) { -#ifndef IOS +#ifndef FILAMENT_IOS LinearImage image(c->width, c->height, 4); image = toLinearWithAlpha(c->width, c->height, c->width * 4, (uint8_t*) buffer); diff --git a/filament/backend/test/test_Blit.cpp b/filament/backend/test/test_Blit.cpp index 8ba0be44c9..b664c864d2 100644 --- a/filament/backend/test/test_Blit.cpp +++ b/filament/backend/test/test_Blit.cpp @@ -24,7 +24,7 @@ #include -#ifndef IOS +#ifndef FILAMENT_IOS #include #include #endif @@ -67,7 +67,7 @@ struct ScreenshotParams { uint32_t pixelHashResult; }; -#ifdef IOS +#ifdef FILAMENT_IOS static void dumpScreenshot(DriverApi& dapi, Handle rt, ScreenshotParams* params) {} #else static void dumpScreenshot(DriverApi& dapi, Handle rt, ScreenshotParams* params) { diff --git a/filament/backend/test/test_FeedbackLoops.cpp b/filament/backend/test/test_FeedbackLoops.cpp index bb7a83416a..df1aaf5471 100644 --- a/filament/backend/test/test_FeedbackLoops.cpp +++ b/filament/backend/test/test_FeedbackLoops.cpp @@ -31,7 +31,7 @@ #include #include -#ifndef IOS +#ifndef FILAMENT_IOS #include #include @@ -112,7 +112,7 @@ static void dumpScreenshot(DriverApi& dapi, Handle rt) { int w = kTexWidth, h = kTexHeight; const uint32_t* texels = (uint32_t*) buffer; sPixelHashResult = utils::hash::murmur3(texels, size / 4, 0); -#ifndef IOS +#ifndef FILAMENT_IOS LinearImage image(w, h, 4); image = toLinearWithAlpha(w, h, w * 4, (uint8_t*) buffer); std::ofstream pngstrm("feedback.png", std::ios::binary | std::ios::trunc); diff --git a/filament/backend/test/test_ReadPixels.cpp b/filament/backend/test/test_ReadPixels.cpp index ee1a37cd9c..873c344388 100644 --- a/filament/backend/test/test_ReadPixels.cpp +++ b/filament/backend/test/test_ReadPixels.cpp @@ -28,7 +28,7 @@ using namespace filament; using namespace filament::backend; -#ifndef IOS +#ifndef FILAMENT_IOS #include #include @@ -137,7 +137,7 @@ TEST_F(ReadPixelsTest, ReadPixels) { } void exportScreenshot(void* pixelData) const { - #ifndef IOS + #ifndef FILAMENT_IOS const size_t width = readRect.width, height = readRect.height; LinearImage image(width, height, 4); if (format == PixelDataFormat::RGBA && type == PixelDataType::UBYTE) { diff --git a/libs/bluevk/include/bluevk/BlueVK.h b/libs/bluevk/include/bluevk/BlueVK.h index a57c528a25..4fb61191a3 100644 --- a/libs/bluevk/include/bluevk/BlueVK.h +++ b/libs/bluevk/include/bluevk/BlueVK.h @@ -40,7 +40,7 @@ #if defined(__ANDROID__) #define VK_USE_PLATFORM_ANDROID_KHR 1 - #elif defined(IOS) + #elif defined(FILAMENT_IOS) #define VK_USE_PLATFORM_IOS_MVK 1 #elif defined(__linux__) #if defined(FILAMENT_SUPPORTS_XCB) diff --git a/libs/filamentapp/src/FilamentApp.cpp b/libs/filamentapp/src/FilamentApp.cpp index 4b7bbd8c33..e47c95c79a 100644 --- a/libs/filamentapp/src/FilamentApp.cpp +++ b/libs/filamentapp/src/FilamentApp.cpp @@ -645,7 +645,7 @@ FilamentApp::Window::Window(FilamentApp* filamentApp, // This mirrors the logic for choosing a backend given compile-time flags and client having // provided DEFAULT as the backend (see PlatformFactory.cpp) - #if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(IOS) && \ + #if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(FILAMENT_IOS) && \ !defined(__APPLE__) && defined(FILAMENT_DRIVER_SUPPORTS_VULKAN) if (backend == Engine::Backend::DEFAULT) { backend = Engine::Backend::VULKAN; diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index cf3007a67f..2e3439a9a7 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -1733,7 +1733,7 @@ void FAssetLoader::importSkins(FFilamentInstance* instance, const cgltf_data* gl } bool AssetConfigurationExtended::isSupported() { -#if defined(__ANDROID__) || defined(IOS) || defined(__EMSCRIPTEN__) +#if defined(__ANDROID__) || defined(FILAMENT_IOS) || defined(__EMSCRIPTEN__) return false; #else return true; diff --git a/libs/gltfio/src/FFilamentAsset.h b/libs/gltfio/src/FFilamentAsset.h index a1401c37cc..1648ad0d2c 100644 --- a/libs/gltfio/src/FFilamentAsset.h +++ b/libs/gltfio/src/FFilamentAsset.h @@ -60,7 +60,7 @@ #define GLTFIO_WARN(msg) slog.w << msg << io::endl #endif -#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(IOS) +#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(FILAMENT_IOS) #define GLTFIO_USE_FILESYSTEM 0 #else #define GLTFIO_USE_FILESYSTEM 1 diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 47d6055dd3..bdde92b0f6 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -158,7 +158,7 @@ static void printUsage(char* name) { " Specify the backend API: " // Matches logic in filament/backend/src/PlatformFactory.cpp for Backend::DEFAULT -#if defined(IOS) || defined(__APPLE__) +#if defined(FILAMENT_IOS) || defined(__APPLE__) "opengl, vulkan, or metal (default)" #elif defined(FILAMENT_DRIVER_SUPPORTS_VULKAN) "opengl, vulkan (default), or metal" diff --git a/third_party/clang/iOS.cmake b/third_party/clang/iOS.cmake index e9ea75e7a4..a935c08f66 100644 --- a/third_party/clang/iOS.cmake +++ b/third_party/clang/iOS.cmake @@ -13,7 +13,7 @@ set(CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS # Necessary for correct install location set(DIST_ARCH ${IOS_ARCH}) -add_definitions(-DIOS) +add_definitions(-DFILAMENT_IOS) set(IOS_MIN_TARGET "11.0") From 29d2d819e345a124057d0af0c6727cc87fb56f6f Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Wed, 8 Jan 2025 21:59:14 +0000 Subject: [PATCH 11/11] Release Filament 1.56.5 --- 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 ee533ab018..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 -fix crash: the 'target_node' of Animation Channel may be nullpointer. \ No newline at end of file diff --git a/README.md b/README.md index 5928aeac6d..d3c1dc1b2b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.56.4' + implementation 'com.google.android.filament:filament-android:1.56.5' } ``` @@ -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.56.4' +pod 'Filament', '~> 1.56.5' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a57b43591f..8ff3e6507b 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.56.6 + +fix crash: the 'target_node' of Animation Channel may be nullpointer. + ## v1.56.5 diff --git a/android/gradle.properties b/android/gradle.properties index bc0e5cf72b..7082c1eab1 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.56.4 +VERSION_NAME=1.56.5 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 8401c38953..c6378573e3 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.56.4" + spec.version = "1.56.5" 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.56.4/filament-v1.56.4-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.5/filament-v1.56.5-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 e6fa858d91..e78ccf5f93 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.56.4", + "version": "1.56.5", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",