diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml index ae7efb2ebe..9745f29131 100644 --- a/.github/workflows/presubmit.yml +++ b/.github/workflows/presubmit.yml @@ -92,27 +92,33 @@ jobs: test-renderdiff: name: test-renderdiff - runs-on: ubuntu-22.04-4core - + runs-on: macos-14-xlarge steps: - uses: actions/checkout@v4.1.6 - - uses: ./.github/actions/ubuntu-apt-add-src + - name: Set up Homebrew + id: set-up-homebrew + uses: Homebrew/actions/setup-homebrew@master + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install python prereqs + run: pip install mako setuptools pyyaml - name: Run script run: | - echo "Disabled renderdiff due to Mesa -> Currently planned outage: 2025-03-16 -> 2025-03-22" -# source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh + bash test/renderdiff/test.sh - uses: actions/upload-artifact@v4 with: name: presubmit-renderdiff-result path: ./out/renderdiff_tests - validate-wgsl-pipeline: - name: validate-wgsl-pipeline - runs-on: ubuntu-22.04-4core + validate-wgsl-webgpu: + name: validate-wgsl-webgpu + runs-on: ubuntu-22.04-8core steps: - uses: actions/checkout@v4.1.6 - name: Run build script - run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat + run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament - name: Run test - run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl* \ No newline at end of file + run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl* diff --git a/CMakeLists.txt b/CMakeLists.txt index f00a15c1ec..c81f49fe70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,14 +139,14 @@ else() set(LINUX FALSE) endif() -if (LINUX) - if (NOT FILAMENT_OSMESA_PATH STREQUAL "") - if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/) - message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}") - endif() - set(FILAMENT_SUPPORTS_OSMESA TRUE) +if (NOT FILAMENT_OSMESA_PATH STREQUAL "") + if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/) + message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}") endif() + set(FILAMENT_SUPPORTS_OSMESA TRUE) +endif() +if (LINUX) if (FILAMENT_SUPPORTS_WAYLAND) add_definitions(-DFILAMENT_SUPPORTS_WAYLAND) set(FILAMENT_SUPPORTS_X11 FALSE) @@ -184,6 +184,12 @@ if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE) set(IS_HOST_PLATFORM TRUE) endif() +if (APPLE) + if (FILAMENT_SUPPORTS_OSMESA) + add_definitions(-DFILAMENT_SUPPORTS_OSMESA) + endif() +endif() + if (WIN32) # Link statically against c/c++ lib to avoid missing redistriburable such as # "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users diff --git a/README.md b/README.md index 54795d7a83..ce0adf1558 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.58.0' + implementation 'com.google.android.filament:filament-android:1.58.1' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.58.0' +pod 'Filament', '~> 1.58.1' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e2b39c788f..8c9612ce22 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,10 @@ A new header is inserted each time a *tag* is created. Instead, if you are authoring a PR for the main branch, add your release note to [NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md). +## v1.58.2 + +- engine: Generate 1D instead of 3D LUTs for color grading whenever possible. + ## v1.58.1 diff --git a/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java b/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java index 680e2585b8..e0397b199b 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java +++ b/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java @@ -46,9 +46,8 @@ import static com.google.android.filament.Asserts.assertFloat4In; * *

Performance

* - * Creating a new ColorGrading object may be more expensive than other Filament objects as a - * 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on - * the CPU. + * Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may + * need to be generated. The generation of this LUT, if necessary, may happen on the CPU. * *

Ordering

* @@ -160,6 +159,10 @@ public class ColorGrading { * quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit * LUT, and a ultra quality will use a 64x64x64 16 bit LUT. * + * This setting has no effect if generating a 1D LUT. + * + * This overrides the values set by format() and dimensions(). + * * The default quality is {@link QualityLevel#MEDIUM}. * * @param qualityLevel The desired quality of the color grading process @@ -175,6 +178,8 @@ public class ColorGrading { * When color grading is implemented using a 3D LUT, this sets the texture format of * of the LUT. This overrides the value set by quality(). * + * This setting has no effect if generating a 1D LUT. + * * The default is INTEGER * * @param format The desired format of the 3D LUT. @@ -190,6 +195,8 @@ public class ColorGrading { * When color grading is implemented using a 3D LUT, this sets the dimension of the LUT. * This overrides the value set by quality(). * + * This setting has no effect if generating a 1D LUT. + * * The default is 32 * * @param dim The desired dimension of the LUT. Between 16 and 64. @@ -616,4 +623,3 @@ public class ColorGrading { private static native long nBuilderBuild(long nativeBuilder, long nativeEngine); } - diff --git a/android/filament-android/src/main/java/com/google/android/filament/ToneMapper.java b/android/filament-android/src/main/java/com/google/android/filament/ToneMapper.java index c3d3490441..89b12541c2 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/ToneMapper.java +++ b/android/filament-android/src/main/java/com/google/android/filament/ToneMapper.java @@ -31,8 +31,6 @@ package com.google.android.filament; *
  • DisplayRangeToneMapper
  • * * - * - * You can create custom tone mapping operators by subclassing ToneMapper. */ public class ToneMapper { private final long mNativeObject; diff --git a/android/gradle.properties b/android/gradle.properties index 3833fd5bca..3007050a8a 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.58.0 +VERSION_NAME=1.58.1 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/build/linux/ci-common.sh b/build/linux/ci-common.sh index c03ed4eeee..7d88065205 100755 --- a/build/linux/ci-common.sh +++ b/build/linux/ci-common.sh @@ -31,7 +31,7 @@ if [[ "$GITHUB_WORKFLOW" ]]; then sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev # For dawn - sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev + sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100 sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100 diff --git a/docs/Materials.md.html b/docs/Materials.md.html index fae697661c..7671c8f97c 100644 --- a/docs/Materials.md.html +++ b/docs/Materials.md.html @@ -78,26 +78,27 @@ in table [standardProperties]. Property | Definition -----------------------:|:--------------------- **baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces -**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) **roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections +**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) **reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections -**sheenColor** | Strength of the sheen layer -**sheenRoughness** | Perceived smoothness or roughness of the sheen layer +**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 **clearCoat** | Strength of the clear coat layer **clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer +**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_) **anisotropy** | Amount of anisotropy in either the tangent or bitangent direction **anisotropyDirection** | Local surface direction in tangent space -**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 -**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_) -**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality -**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_) -**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass -**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending` -**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance -**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is -**absorption** | Absorption factor for refractive objects -**microThickness** | Thickness of the thin layer of refractive objects **thickness** | Thickness of the solid volume of refractive objects +**sheenColor** | Strength of the sheen layer +**sheenRoughness** | Perceived smoothness or roughness of the sheen layer +**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass +**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_) +**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending` +**absorption** | Absorption factor for refractive objects +**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is +**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance +**microThickness** | Thickness of the thin layer of refractive objects +**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality +**shadowStrength** | Strength factor between 0 and 1 for all shadows received by this material [Table [standardProperties]: Properties of the standard model] The type and range of each property is described in table [standardPropertiesTypes]. diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 6f66f1f457..24c7a15587 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -108,8 +108,12 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3) list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm) list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm) elseif (APPLE) - list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm) - list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm) + if (FILAMENT_SUPPORTS_OSMESA) + list(APPEND SRCS src/opengl/platforms/PlatformOSMesa.cpp) + else() + list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm) + list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm) + endif() elseif (WEBGL) list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp) elseif (LINUX) @@ -173,10 +177,12 @@ endif() if (FILAMENT_SUPPORTS_VULKAN) list(APPEND SRCS include/backend/platforms/VulkanPlatform.h - src/vulkan/caching/VulkanDescriptorSetManager.cpp - src/vulkan/caching/VulkanDescriptorSetManager.h - src/vulkan/caching/VulkanPipelineLayoutCache.cpp - src/vulkan/caching/VulkanPipelineLayoutCache.h + src/vulkan/VulkanDescriptorSetCache.cpp + src/vulkan/VulkanDescriptorSetCache.h + src/vulkan/VulkanDescriptorSetLayoutCache.cpp + src/vulkan/VulkanDescriptorSetLayoutCache.h + src/vulkan/VulkanPipelineLayoutCache.cpp + src/vulkan/VulkanPipelineLayoutCache.h src/vulkan/memory/ResourceManager.cpp src/vulkan/memory/ResourceManager.h src/vulkan/memory/ResourcePointer.h @@ -416,9 +422,12 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS -Wl,--exclude-libs,bluegl ) -if (LINUX AND FILAMENT_SUPPORTS_OSMESA) - set(OSMESA_COMPILE_FLAGS - -I${FILAMENT_OSMESA_PATH}/include/GL) +if (FILAMENT_SUPPORTS_OSMESA) + if (LINUX) + set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL) + elseif (APPLE) + set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include) + endif() endif() if (MSVC) diff --git a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h index ecd8fc8ab4..d3d1f3a60c 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h +++ b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h @@ -23,6 +23,7 @@ #include #include +#include #include @@ -43,8 +44,21 @@ public: PlatformEGLAndroid() noexcept; ~PlatformEGLAndroid() noexcept override; -protected: + /** + * Creates an ExternalImage from a EGLImageKHR + */ + ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept; + struct ExternalImageDescAndroid { + uint32_t width; // Texture width + uint32_t height; // Texture height + TextureFormat format;// Texture format + TextureUsage usage; // Texture usage flags + }; + + ExternalImageDescAndroid getExternalImageDesc(ExternalImageHandle externalImage) noexcept; + +protected: // -------------------------------------------------------------------------------------------- // Platform Interface @@ -57,11 +71,6 @@ protected: Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override; - /** - * Creates an ExternalImage from a EGLImageKHR - */ - ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept; - // -------------------------------------------------------------------------------------------- // OpenGLPlatform Interface @@ -95,15 +104,26 @@ protected: */ AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override; - bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; struct ExternalImageEGLAndroid : public ExternalImageEGL { AHardwareBuffer* aHardwareBuffer = nullptr; + uint32_t width; // Texture width + uint32_t height; // Texture height + TextureFormat format;// Texture format + TextureUsage usage; // Texture usage flags bool sRGB = false; + protected: ~ExternalImageEGLAndroid() override; }; + bool setExternalImage(ExternalImageHandleRef externalImage, + ExternalTexture* texture) noexcept override; + bool setImage(ExternalImageEGLAndroid const* eglExternalImage, + ExternalTexture* texture) noexcept; + protected: bool makeCurrent(ContextType type, SwapChain* drawSwapChain, diff --git a/filament/backend/include/backend/platforms/PlatformOSMesa.h b/filament/backend/include/backend/platforms/PlatformOSMesa.h index a1a72fc6f7..5f6658f94d 100644 --- a/filament/backend/include/backend/platforms/PlatformOSMesa.h +++ b/filament/backend/include/backend/platforms/PlatformOSMesa.h @@ -21,7 +21,12 @@ #include "bluegl/BlueGL.h" +#if defined(__linux__) #include +#elif defined(__APPLE__) +#undef GLAPI +#include +#endif #include #include diff --git a/filament/backend/include/backend/platforms/VulkanPlatform.h b/filament/backend/include/backend/platforms/VulkanPlatform.h index 404b67249b..10f6dff3ab 100644 --- a/filament/backend/include/backend/platforms/VulkanPlatform.h +++ b/filament/backend/include/backend/platforms/VulkanPlatform.h @@ -368,8 +368,16 @@ public: uint32_t internalFormat, VkImage image, VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle); +protected: + virtual ExtensionSet getSwapchainInstanceExtensions() const; + + using SurfaceBundle = std::tuple; + virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, + uint64_t flags) const noexcept; + private: - static ExtensionSet getSwapchainInstanceExtensions(); + // Platform dependent helper methods + static ExtensionSet getSwapchainInstanceExtensionsImpl(); static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage, VkDevice device); @@ -386,8 +394,7 @@ private: VkComponentMapping swizzle); // Platform dependent helper methods - using SurfaceBundle = std::tuple; - static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, + static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance, uint64_t flags) noexcept; friend struct VulkanPlatformPrivate; diff --git a/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h b/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h index ca6cd888ae..f08ff384cc 100644 --- a/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h +++ b/filament/backend/include/backend/platforms/VulkanPlatformAndroid.h @@ -17,27 +17,55 @@ #ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H #define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H -#include +#include +#include #include -namespace filament::backend::fvkandroid { +namespace filament::backend { -struct ExternalImageVulkanAndroid : public Platform::ExternalImage { - AHardwareBuffer* aHardwareBuffer = nullptr; - bool sRGB = false; - unsigned int width; // Texture width - unsigned int height; // Texture height - TextureFormat format; // Texture format - TextureUsage usage; // Texture usage flags +class VulkanPlatformAndroid : public VulkanPlatform { +public: + Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer, + bool sRGB) noexcept; + + struct UTILS_PUBLIC ExternalImageDescAndroid { + uint32_t width; // Texture width + uint32_t height; // Texture height + TextureFormat format;// Texture format + TextureUsage usage; // Texture usage flags + }; + + ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc( + ExternalImageHandleRef externalImage) const noexcept; protected: - ~ExternalImageVulkanAndroid() override; + struct ExternalImageVulkanAndroid : public Platform::ExternalImage { + AHardwareBuffer* aHardwareBuffer = nullptr; + bool sRGB = false; + unsigned int width; // Texture width + unsigned int height; // Texture height + TextureFormat format;// Texture format + TextureUsage usage; // Texture usage flags + + protected: + ~ExternalImageVulkanAndroid() override; + }; + + virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage); + + using ImageData = VulkanPlatform::ImageData; + virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage, + const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, + VkImageUsageFlags usage); + + virtual ExtensionSet getSwapchainInstanceExtensions() const; + + using SurfaceBundle = VulkanPlatform::SurfaceBundle; + virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, + uint64_t flags) const noexcept; }; -Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, - bool sRGB) noexcept; +}// namespace filament::backend -} // namespace filament::backend::fvkandroid - -#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H +#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H diff --git a/filament/backend/src/PlatformFactory.cpp b/filament/backend/src/PlatformFactory.cpp index bf1ec35176..d5055daee5 100644 --- a/filament/backend/src/PlatformFactory.cpp +++ b/filament/backend/src/PlatformFactory.cpp @@ -19,6 +19,11 @@ #include #include +// We need to keep this up top for the linux (X11) name collisions. +#if defined(FILAMENT_SUPPORTS_WEBGPU) + #include "backend/platforms/WebGPUPlatform.h" +#endif + #if defined(__ANDROID__) #include #if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) @@ -30,7 +35,11 @@ #endif #elif defined(__APPLE__) #if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) - #include + #if defined(FILAMENT_SUPPORTS_OSMESA) + #include + #else + #include + #endif #endif #elif defined(__linux__) #if defined(FILAMENT_SUPPORTS_X11) @@ -55,7 +64,11 @@ #endif #if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN) - #include "backend/platforms/VulkanPlatform.h" + #if defined(__ANDROID__) + #include "backend/platforms/VulkanPlatformAndroid.h" + #else + #include "backend/platforms/VulkanPlatform.h" + #endif #endif #if defined (FILAMENT_SUPPORTS_METAL) @@ -65,9 +78,6 @@ filament::backend::Platform* createDefaultMetalPlatform(); #endif #include "noop/PlatformNoop.h" -#if defined(FILAMENT_SUPPORTS_WEBGPU) - #include "backend/platforms/WebGPUPlatform.h" -#endif namespace filament::backend { @@ -104,7 +114,11 @@ Platform* PlatformFactory::create(Backend* backend) noexcept { } if (*backend == Backend::VULKAN) { #if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN) - return new VulkanPlatform(); + #if defined(__ANDROID__) + return new VulkanPlatformAndroid(); + #else + return new VulkanPlatform(); + #endif #else return nullptr; #endif @@ -132,7 +146,11 @@ Platform* PlatformFactory::create(Backend* backend) noexcept { #elif defined(FILAMENT_IOS) return new PlatformCocoaTouchGL(); #elif defined(__APPLE__) - return new PlatformCocoaGL(); + #if defined(FILAMENT_SUPPORTS_OSMESA) + return new PlatformOSMesa(); + #else + return new PlatformCocoaGL(); + #endif #elif defined(__linux__) #if defined(FILAMENT_SUPPORTS_X11) return new PlatformGLX(); diff --git a/filament/backend/src/noop/PlatformNoop.cpp b/filament/backend/src/noop/PlatformNoop.cpp index 70e222e55e..5fb65c683e 100644 --- a/filament/backend/src/noop/PlatformNoop.cpp +++ b/filament/backend/src/noop/PlatformNoop.cpp @@ -20,7 +20,7 @@ namespace filament::backend { -Driver* PlatformNoop::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { +Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { return NoopDriver::create(); } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 9500c124c7..1c4a9a6e2e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -148,8 +148,8 @@ using namespace utils; namespace filament::backend { Driver* OpenGLDriverFactory::create( - OpenGLPlatform* const platform, - void* const sharedGLContext, + OpenGLPlatform* platform, + void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { return OpenGLDriver::create(platform, sharedGLContext, driverConfig); } @@ -159,10 +159,10 @@ using namespace GLUtils; // ------------------------------------------------------------------------------------------------ UTILS_NOINLINE -OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform, - void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept { +OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform, + void* /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept { assert_invariant(platform); - OpenGLPlatform* const ec = platform; + OpenGLPlatform* ec = platform; #if 0 // this is useful for development, but too verbose even for debug builds @@ -230,7 +230,7 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform, constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U; Platform::DriverConfig validConfig{ driverConfig }; validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize); - OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig); + OpenGLDriver* driver = new(std::nothrow) OpenGLDriver(ec, validConfig); return driver; } diff --git a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm index e37e61a109..681a6a81b9 100644 --- a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm +++ b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm @@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept { delete pImpl; } -Driver* PlatformCocoaTouchGL::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { +Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext; EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup]; diff --git a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp index e32adb864e..a321eef83f 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "opengl/GLUtils.h" @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -231,26 +234,133 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext, return driver; } -PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default; +PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() { + if (__builtin_available(android 26, *)) { + if (aHardwareBuffer) { + AHardwareBuffer_release(aHardwareBuffer); + } + } +} -Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept { - auto* const p = new(std::nothrow) ExternalImageEGLAndroid; - p->aHardwareBuffer = const_cast(buffer); - p->sRGB = sRGB; - return ExternalImageHandle{ p }; +Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, + bool sRGB) noexcept { + if (__builtin_available(android 26, *)) { + auto* const p = new (std::nothrow) ExternalImageEGLAndroid; + auto hardwareBuffer = const_cast(buffer); + AHardwareBuffer_acquire(hardwareBuffer); + p->aHardwareBuffer = hardwareBuffer; + p->sRGB = sRGB; + AHardwareBuffer_Desc hardwareBufferDescription = {}; + AHardwareBuffer_describe(hardwareBuffer, &hardwareBufferDescription); + p->height = hardwareBufferDescription.height; + p->width = hardwareBufferDescription.width; + auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB); + p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat); + return ExternalImageHandle{ p }; + } + + return Platform::ExternalImageHandle{}; +} + +PlatformEGLAndroid::ExternalImageDescAndroid PlatformEGLAndroid::getExternalImageDesc( + ExternalImageHandle externalImage) noexcept { + auto const* const eglExternalImage = + static_cast(externalImage.get()); + ExternalImageDescAndroid metadata = {}; + if (!eglExternalImage) { + return metadata; + } + metadata.height = eglExternalImage->height; + metadata.width = eglExternalImage->width; + metadata.format = eglExternalImage->format; + metadata.usage = eglExternalImage->usage; + return metadata; } bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage, UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { - auto const* const eglExternalImage = static_cast(externalImage.get()); + auto const* const eglExternalImage = + static_cast(externalImage.get()); if (eglExternalImage->aHardwareBuffer) { - // TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer - return true; + return PlatformEGLAndroid::setImage(eglExternalImage, texture); } // not a AHardwareBuffer, fallback to the inherited version return PlatformEGL::setExternalImage(externalImage, texture); } +OpenGLPlatform::ExternalTexture* PlatformEGLAndroid::createExternalImageTexture() noexcept { + ExternalTexture* outTexture = new (std::nothrow) ExternalTexture{}; + glGenTextures(1, &outTexture->id); + return outTexture; +} + +void PlatformEGLAndroid::destroyExternalImageTexture(ExternalTexture* texture) noexcept { + glDeleteTextures(1, &texture->id); + delete texture; +} + +bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImage, + UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { + AHardwareBuffer* hardwareBuffer = eglExternalImage->aHardwareBuffer; + + // Get the EGL client buffer from AHardwareBuffer + EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer); + EGLint imageAttrs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE, EGL_NONE, // Reserve space + EGL_NONE, EGL_NONE, // Reserve space + EGL_NONE // Ensure the list always ends with EGL_NONE + }; + int attrIndex = 2; + if (eglExternalImage->sRGB) { + imageAttrs[attrIndex++] = EGL_GL_COLORSPACE; + imageAttrs[attrIndex++] = EGL_GL_COLORSPACE_SRGB; + } + + if (static_cast(eglExternalImage->usage & TextureUsage::PROTECTED)) { + imageAttrs[attrIndex++] = EGL_PROTECTED_CONTENT_EXT; + imageAttrs[attrIndex++] = EGL_TRUE; + } + // Create an EGLImage from the client buffer + EGLImageKHR eglImage = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs); + if (eglImage == EGL_NO_IMAGE_KHR) { + // Handle error + slog.e << "Failed to create EGL image" << io::endl; + glDeleteTextures(1, &texture->id); + return false; + } + + // Create and bind the OpenGL texture + GLint prevActiveTexture, prevTexture; + glGetIntegerv(GL_ACTIVE_TEXTURE, &prevActiveTexture); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTexture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->id); + GLenum error = glGetError(); + if (UTILS_UNLIKELY(error != GL_NO_ERROR)) { + slog.e << "Error after glBindTexture: " << error << io::endl; + glDeleteTextures(1, &texture->id); + eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage); + glActiveTexture(prevActiveTexture); + glBindTexture(GL_TEXTURE_2D, prevTexture); + return false; + } + glEGLImageTargetTexture2DOES(texture->target, static_cast(eglImage)); + error = glGetError(); + if (UTILS_UNLIKELY(error != GL_NO_ERROR)) { + slog.e << "Error after glEGLImageTargetTexture2DOES: " << error << io::endl; + glDeleteTextures(1, &texture->id); + eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage); + glActiveTexture(prevActiveTexture); + glBindTexture(GL_TEXTURE_2D, prevTexture); + return false; + } + glActiveTexture(prevActiveTexture); + glBindTexture(GL_TEXTURE_2D, prevTexture); + return true; +} + void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept { EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW); if (currentDrawSurface != EGL_NO_SURFACE) { diff --git a/filament/backend/src/opengl/platforms/PlatformGLX.cpp b/filament/backend/src/opengl/platforms/PlatformGLX.cpp index f7a64bda62..c3b1a76ff8 100644 --- a/filament/backend/src/opengl/platforms/PlatformGLX.cpp +++ b/filament/backend/src/opengl/platforms/PlatformGLX.cpp @@ -128,7 +128,7 @@ namespace filament::backend { using namespace backend; -Driver* PlatformGLX::createDriver(void* const sharedGLContext, +Driver* PlatformGLX::createDriver(void* sharedGLContext, const DriverConfig& driverConfig) noexcept { loadLibraries(); // Get the display device diff --git a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp index 831e30cc62..16d52de0d2 100644 --- a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp +++ b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp @@ -22,9 +22,11 @@ #include #include +#if defined(__linux__) // This is to ensure that linking during compilation will not fail even if // OSMesaGetProcAddress is not linked. __attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*); +#endif namespace filament::backend { @@ -48,20 +50,27 @@ struct OSMesaSwapchain { struct OSMesaAPI { private: - using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext); + using CreateContextAttribsFunc = OSMesaContext (*)(const int *, OSMesaContext); using DestroyContextFunc = GLboolean (*)(OSMesaContext); using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, GLsizei height); using GetProcAddressFunc = OSMESAproc (*)(const char* funcName); public: - CreateContextFunc fOSMesaCreateContext; + CreateContextAttribsFunc fOSMesaCreateContextAttribs; DestroyContextFunc fOSMesaDestroyContext; MakeCurrentFunc fOSMesaMakeCurrent; GetProcAddressFunc fOSMesaGetProcAddress; OSMesaAPI() { - constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + static constexpr char const* libraryNames[] = { +#if defined(__linux__) + "libOSMesa.so", + "libosmesa.so", +#elif defined(__APPLE__) + "libOSMesa.dylib", +#endif + }; for (char const* libName: libraryNames) { mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW); if (mLib) { @@ -71,22 +80,24 @@ public: if (mLib) { // Loading from a libosmesa.os fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress"); - } else { + } +#if defined(__linux__) + else { // Filament is built into a .so fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress"); } - if (!fOSMesaGetProcAddress) { // Statically linking osmesa fOSMesaGetProcAddress = OSMesaGetProcAddress; } +#endif // __linux__ FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress) << "Unable to link against libOSMesa to create a software GL context"; - fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext"); - fOSMesaDestroyContext = - (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext"); + fOSMesaCreateContextAttribs = + (CreateContextAttribsFunc) fOSMesaGetProcAddress("OSMesaCreateContextAttribs"); + fOSMesaDestroyContext = (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext"); fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent"); } @@ -101,14 +112,24 @@ private: }// anonymous namespace -Driver* PlatformOSMesa::createDriver(void* const sharedGLContext, +Driver* PlatformOSMesa::createDriver(void* sharedGLContext, const DriverConfig& driverConfig) noexcept { + OSMesaAPI* api = new OSMesaAPI(); mOsMesaApi = api; + static constexpr int attribs[] = { + OSMESA_FORMAT, GL_RGBA, + OSMESA_DEPTH_BITS, 24, + OSMESA_STENCIL_BITS, 8, + OSMESA_ACCUM_BITS, 0, + OSMESA_PROFILE, OSMESA_CORE_PROFILE, + 0, + }; + FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr) << "shared GL context is not supported with PlatformOSMesa"; - mContext = api->fOSMesaCreateContext(GL_RGBA, NULL); + mContext = api->fOSMesaCreateContextAttribs(attribs, NULL); // We need to do a no-op makecurrent here so that the context will be in a correct state before // any GL calls. diff --git a/filament/backend/src/opengl/platforms/PlatformWGL.cpp b/filament/backend/src/opengl/platforms/PlatformWGL.cpp index 57c3e4668d..094ecf3e2c 100644 --- a/filament/backend/src/opengl/platforms/PlatformWGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformWGL.cpp @@ -75,7 +75,7 @@ struct WGLSwapChain { static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr; -Driver* PlatformWGL::createDriver(void* const sharedGLContext, +Driver* PlatformWGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { int result = 0; int pixelFormat = 0; diff --git a/filament/backend/src/opengl/platforms/PlatformWebGL.cpp b/filament/backend/src/opengl/platforms/PlatformWebGL.cpp index a6d4c5c5a2..4f522b2991 100644 --- a/filament/backend/src/opengl/platforms/PlatformWebGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformWebGL.cpp @@ -20,7 +20,7 @@ namespace filament::backend { using namespace backend; -Driver* PlatformWebGL::createDriver(void* const sharedGLContext, +Driver* PlatformWebGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig); } diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp b/filament/backend/src/vulkan/VulkanDescriptorSetCache.cpp similarity index 73% rename from filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp rename to filament/backend/src/vulkan/VulkanDescriptorSetCache.cpp index 570dcc5df2..eb89ad8eab 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp +++ b/filament/backend/src/vulkan/VulkanDescriptorSetCache.cpp @@ -14,35 +14,25 @@ * limitations under the License. */ -#include "VulkanDescriptorSetManager.h" +#include "VulkanDescriptorSetCache.h" -#include "vulkan/VulkanCommands.h" -#include "vulkan/VulkanHandles.h" -#include "vulkan/VulkanConstants.h" +#include "VulkanCommands.h" +#include "VulkanHandles.h" +#include "VulkanConstants.h" #include #include -#include - #include #include -#include #include namespace filament::backend { namespace { -using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask; using DescriptorCount = VulkanDescriptorSetLayout::Count; -using DescriptorSetLayoutArray = VulkanDescriptorSetManager::DescriptorSetLayoutArray; -using BitmaskGroupHashFn = utils::hash::MurmurHashFn; -struct BitmaskGroupEqual { - bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const { - return k1 == k2; - } -}; +using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray; // We create a pool for each layout as defined by the number of descriptors of each type. For // example, a layout of @@ -199,72 +189,12 @@ struct Equal { } }; -template -uint32_t createBindings(VkDescriptorSetLayoutBinding* toBind, uint32_t count, VkDescriptorType type, - Bitmask const& mask) { - Bitmask alreadySeen; - mask.forEachSetBit([&](size_t index) { - VkShaderStageFlags stages = 0; - uint32_t binding = 0; - if (index < fvkutils::getFragmentStageShift()) { - binding = (uint32_t) index; - stages |= VK_SHADER_STAGE_VERTEX_BIT; - auto fragIndex = index + fvkutils::getFragmentStageShift(); - if (mask.test(fragIndex)) { - stages |= VK_SHADER_STAGE_FRAGMENT_BIT; - alreadySeen.set(fragIndex); - } - } else if (!alreadySeen.test(index)) { - // We are in fragment stage bits - binding = (uint32_t) (index - fvkutils::getFragmentStageShift()); - stages |= VK_SHADER_STAGE_FRAGMENT_BIT; - } - - if (stages) { - toBind[count++] = { - .binding = binding, - .descriptorType = type, - .descriptorCount = 1, - .stageFlags = stages, - }; - } - }); - return count; -} - -inline VkDescriptorSetLayout createLayout(VkDevice device, BitmaskGroup const& bitmaskGroup) { - // Note that the following *needs* to be static so that VkDescriptorSetLayoutCreateInfo will not - // refer to stack memory. - VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS]; - uint32_t count = 0; - - count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - bitmaskGroup.dynamicUbo); - count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmaskGroup.ubo); - count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - bitmaskGroup.sampler); - count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - bitmaskGroup.inputAttachment); - - assert_invariant(count != 0 && "Need at least one binding for descriptor set layout."); - VkDescriptorSetLayoutCreateInfo dlinfo = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .bindingCount = count, - .pBindings = toBind, - }; - - VkDescriptorSetLayout layout; - vkCreateDescriptorSetLayout(device, &dlinfo, VKALLOC, &layout); - return layout; -} - } // anonymous namespace // This is an ever-expanding pool of sets where it // 1. Keeps a list of smaller pools of different layout-dimensions. // 2. Will add a pool if existing pool are not compatible with the requested layout o runs out. -class VulkanDescriptorSetManager::DescriptorInfinitePool { +class VulkanDescriptorSetCache::DescriptorInfinitePool { private: static constexpr uint16_t EXPECTED_SET_COUNT = 10; static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5; @@ -319,61 +249,34 @@ private: std::vector> mPools; }; -class VulkanDescriptorSetManager::DescriptorSetLayoutManager { -public: - DescriptorSetLayoutManager(VkDevice device) - : mDevice(device) {} - VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks) { - if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) { - return itr->second; - } - auto vklayout = createLayout(mDevice, bitmasks); - mVkLayouts[bitmasks] = vklayout; - return vklayout; - } - - ~DescriptorSetLayoutManager() { - for (auto& itr: mVkLayouts) { - vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC); - } - } - -private: - VkDevice mDevice; - tsl::robin_map - mVkLayouts; -}; - -VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, +VulkanDescriptorSetCache::VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager) : mDevice(device), mResourceManager(resourceManager), - mLayoutManager(std::make_unique(device)), mDescriptorPool(std::make_unique(device)) {} -VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default; +VulkanDescriptorSetCache::~VulkanDescriptorSetCache() = default; -void VulkanDescriptorSetManager::terminate() noexcept{ - mLayoutManager.reset(); +void VulkanDescriptorSetCache::terminate() noexcept{ mDescriptorPool.reset(); clearHistory(); } // bind() is not really binding the set but just stashing until we have all the info // (pipelinelayout). -void VulkanDescriptorSetManager::bind(uint8_t setIndex, +void VulkanDescriptorSetCache::bind(uint8_t setIndex, fvkmemory::resource_ptr set, backend::DescriptorSetOffsetArray&& offsets) { set->setOffsets(std::move(offsets)); mStashedSets[setIndex] = set; } -void VulkanDescriptorSetManager::unbind(uint8_t setIndex) { +void VulkanDescriptorSetCache::unbind(uint8_t setIndex) { mStashedSets[setIndex] = {}; } -void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, +void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) { // setMask indicates the set of descriptor sets the driver wants to bind, curMask is the // actual set of sets that *needs* to be bound. @@ -412,7 +315,7 @@ void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, }; } -void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr set, +void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr set, uint8_t binding, fvkmemory::resource_ptr bufferObject, VkDeviceSize offset, VkDeviceSize size) noexcept { VkDescriptorBufferInfo const info = { @@ -438,7 +341,7 @@ void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptracquire(bufferObject); } -void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr set, +void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr set, uint8_t binding, fvkmemory::resource_ptr texture, VkSampler sampler) noexcept { VkDescriptorImageInfo info{ @@ -470,13 +373,13 @@ void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptracquire(texture); } -void VulkanDescriptorSetManager::updateInputAttachment( +void VulkanDescriptorSetCache::updateInputAttachment( fvkmemory::resource_ptr set, VulkanAttachment const& attachment) noexcept { - // TOOD: fill-in this region + // TOOD: fill this in. } -fvkmemory::resource_ptr VulkanDescriptorSetManager::createSet( +fvkmemory::resource_ptr VulkanDescriptorSetCache::createSet( Handle handle, fvkmemory::resource_ptr layout) { auto const vkSet = mDescriptorPool->obtainSet(layout); auto const& count = layout->count; @@ -492,12 +395,7 @@ fvkmemory::resource_ptr VulkanDescriptorSetManager::createS }); } -void VulkanDescriptorSetManager::initVkLayout( - fvkmemory::resource_ptr layout) { - layout->setVkLayout(mLayoutManager->getVkLayout(layout->bitmask)); -} - -void VulkanDescriptorSetManager::clearHistory() { +void VulkanDescriptorSetCache::clearHistory() { mStashedSets = {}; } diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h b/filament/backend/src/vulkan/VulkanDescriptorSetCache.h similarity index 76% rename from filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h rename to filament/backend/src/vulkan/VulkanDescriptorSetCache.h index 87aa076213..898b314be9 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h +++ b/filament/backend/src/vulkan/VulkanDescriptorSetCache.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H -#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H +#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H +#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H -#include "vulkan/VulkanHandles.h" +#include "VulkanHandles.h" #include "vulkan/memory/ResourcePointer.h" #include "vulkan/utils/Definitions.h" // For DescriptorSetMask @@ -34,20 +34,16 @@ namespace filament::backend { -// [GDSR]: Great-Descriptor-Set-Refactor: As of 03/20/24, the Filament frontend is planning to -// introduce descriptor set. This PR will arrive before that change is complete. As such, some of -// the methods introduced here will be obsolete, and certain logic will be generalized. - -// Abstraction over the pool and the layout cache. -class VulkanDescriptorSetManager { +// Abstraction over the descriptor set pool. +class VulkanDescriptorSetCache { public: static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT = VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT; using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray; - VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager); - ~VulkanDescriptorSetManager(); + VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager); + ~VulkanDescriptorSetCache(); void terminate() noexcept; @@ -72,12 +68,9 @@ public: fvkmemory::resource_ptr createSet(Handle handle, fvkmemory::resource_ptr layout); - void initVkLayout(fvkmemory::resource_ptr layout); - void clearHistory(); private: - class DescriptorSetLayoutManager; class DescriptorInfinitePool; using DescriptorSetArray = @@ -85,7 +78,6 @@ private: VkDevice mDevice; fvkmemory::ResourceManager* mResourceManager; - std::unique_ptr mLayoutManager; std::unique_ptr mDescriptorPool; std::pair mInputAttachment; DescriptorSetArray mStashedSets = {}; @@ -99,4 +91,4 @@ private: }// namespace filament::backend -#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H +#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H diff --git a/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.cpp b/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.cpp new file mode 100644 index 0000000000..666827cd19 --- /dev/null +++ b/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.cpp @@ -0,0 +1,110 @@ +/* + * 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 "VulkanDescriptorSetLayoutCache.h" + +#include "VulkanHandles.h" + +namespace filament::backend { + +namespace { + +using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask; + +template +uint32_t appendBindings(VkDescriptorSetLayoutBinding* toBind, VkDescriptorType type, + Bitmask const& mask) { + uint32_t count = 0; + Bitmask alreadySeen; + mask.forEachSetBit([&](size_t index) { + VkShaderStageFlags stages = 0; + uint32_t binding = 0; + if (index < fvkutils::getFragmentStageShift()) { + binding = (uint32_t) index; + stages |= VK_SHADER_STAGE_VERTEX_BIT; + auto fragIndex = index + fvkutils::getFragmentStageShift(); + if (mask.test(fragIndex)) { + stages |= VK_SHADER_STAGE_FRAGMENT_BIT; + alreadySeen.set(fragIndex); + } + } else if (!alreadySeen.test(index)) { + // We are in fragment stage bits + binding = (uint32_t) (index - fvkutils::getFragmentStageShift()); + stages |= VK_SHADER_STAGE_FRAGMENT_BIT; + } + + if (stages) { + toBind[count++] = { + .binding = binding, + .descriptorType = type, + .descriptorCount = 1, + .stageFlags = stages, + }; + } + }); + return count; +} + +} // anonymous namespace + +VulkanDescriptorSetLayoutCache::VulkanDescriptorSetLayoutCache(VkDevice device, + fvkmemory::ResourceManager* resourceManager) + : mDevice(device), + mResourceManager(resourceManager) {} + +VulkanDescriptorSetLayoutCache::~VulkanDescriptorSetLayoutCache() = default; + +void VulkanDescriptorSetLayoutCache::terminate() noexcept { + for (auto& itr: mVkLayouts) { + vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC); + } +} + +fvkmemory::resource_ptr VulkanDescriptorSetLayoutCache::createLayout( + Handle handle, backend::DescriptorSetLayout&& info) { + auto layout = fvkmemory::resource_ptr::make(mResourceManager, handle, + info); + VkDescriptorSetLayout vklayout = VK_NULL_HANDLE; + auto const& bitmasks = layout->bitmask; + if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) { + vklayout = itr->second; + } else { + VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS]; + uint32_t count = 0; + count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + bitmasks.dynamicUbo); + count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo); + count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + bitmasks.sampler); + count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + bitmasks.inputAttachment); + + assert_invariant(count != 0 && "Need at least one binding for descriptor set layout."); + VkDescriptorSetLayoutCreateInfo dlinfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .bindingCount = count, + .pBindings = toBind, + }; + + vkCreateDescriptorSetLayout(mDevice, &dlinfo, VKALLOC, &vklayout); + mVkLayouts[bitmasks] = vklayout; + } + layout->setVkLayout(vklayout); + return layout; +} + +} // namespace filament::backend diff --git a/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.h b/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.h new file mode 100644 index 0000000000..a1f6461249 --- /dev/null +++ b/filament/backend/src/vulkan/VulkanDescriptorSetLayoutCache.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H +#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H + +#include "VulkanHandles.h" + +#include "vulkan/memory/ResourcePointer.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace filament::backend { + +class VulkanDescriptorSetLayoutCache { +public: + VulkanDescriptorSetLayoutCache(VkDevice device, fvkmemory::ResourceManager* resourceManager); + ~VulkanDescriptorSetLayoutCache(); + + void terminate() noexcept; + + fvkmemory::resource_ptr createLayout( + Handle handle, backend::DescriptorSetLayout&& info); + +private: + VkDevice mDevice; + fvkmemory::ResourceManager* mResourceManager; + + using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask; + using BitmaskGroupHashFn = utils::hash::MurmurHashFn; + struct BitmaskGroupEqual { + bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const { return k1 == k2; } + }; + + tsl::robin_map + mVkLayouts; +}; + +} // namespace filament::backend + +#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index eb6629bafa..8cfadd3728 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -17,7 +17,6 @@ #include "VulkanDriver.h" #include "CommandStreamDispatcher.h" -#include "DataReshaper.h" #include "SystraceProfile.h" #include "VulkanAsyncHandles.h" #include "VulkanBuffer.h" @@ -35,7 +34,6 @@ #include #include -#include #include #ifndef NDEBUG @@ -44,8 +42,6 @@ using namespace bluevk; -using utils::FixedCapacityVector; - #if defined(__clang__) // Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer // to a stack-allocated variable. @@ -219,7 +215,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex mSamplerCache(mPlatform->getDevice()), mBlitter(mPlatform->getPhysicalDevice(), &mCommands), mReadPixels(mPlatform->getDevice()), - mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager), + mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager), + mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager), mQueryManager(mPlatform->getDevice()), mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported), mStereoscopicType(driverConfig.stereoscopicType) { @@ -329,7 +326,8 @@ void VulkanDriver::terminate() { mPipelineCache.terminate(); mFramebufferCache.reset(); mSamplerCache.terminate(); - mDescriptorSetManager.terminate(); + mDescriptorSetLayoutCache.terminate(); + mDescriptorSetCache.terminate(); mPipelineLayoutCache.terminate(); // Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset. @@ -365,7 +363,7 @@ void VulkanDriver::collectGarbage() { FVK_SYSTRACE_SCOPE(); // Command buffers need to be submitted and completed before other resources can be gc'd. mCommands.gc(); - mDescriptorSetManager.clearHistory(); + mDescriptorSetCache.clearHistory(); mStagePool.gc(); mFramebufferCache.gc(); mPipelineCache.gc(); @@ -408,7 +406,7 @@ void VulkanDriver::updateDescriptorSetBuffer( FVK_SYSTRACE_SCOPE(); auto set = resource_ptr::cast(&mResourceManager, dsh); auto buffer = resource_ptr::cast(&mResourceManager, boh); - mDescriptorSetManager.updateBuffer(set, binding, buffer, offset, size); + mDescriptorSetCache.updateBuffer(set, binding, buffer, offset, size); } void VulkanDriver::updateDescriptorSetTexture( @@ -421,7 +419,7 @@ void VulkanDriver::updateDescriptorSetTexture( auto texture = resource_ptr::cast(&mResourceManager, th); VkSampler const vksampler = mSamplerCache.getSampler(params); - mDescriptorSetManager.updateSampler(set, binding, texture, vksampler); + mDescriptorSetCache.updateSampler(set, binding, texture, vksampler); } void VulkanDriver::flush(int) { @@ -778,8 +776,7 @@ void VulkanDriver::createTimerQueryR(Handle tqh, int) { void VulkanDriver::createDescriptorSetLayoutR(Handle dslh, backend::DescriptorSetLayout&& info) { - auto layout = resource_ptr::make(&mResourceManager, dslh, info); - mDescriptorSetManager.initVkLayout(layout); + auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info)); layout.inc(); } @@ -788,7 +785,7 @@ void VulkanDriver::createDescriptorSetR(Handle dsh, FVK_SYSTRACE_SCOPE(); fvkmemory::resource_ptr layout = fvkmemory::resource_ptr::cast(&mResourceManager, dslh); - auto set = mDescriptorSetManager.createSet(dsh, layout); + auto set = mDescriptorSetCache.createSet(dsh, layout); set.inc(); } @@ -1493,7 +1490,7 @@ void VulkanDriver::nextSubpass(int) { if (mCurrentRenderPass.params.subpassMask & 0x1) { VulkanAttachment& subpassInput = renderTarget->getColor0(); - mDescriptorSetManager.updateInputAttachment({}, subpassInput); + mDescriptorSetCache.updateInputAttachment({}, subpassInput); } } @@ -1820,9 +1817,9 @@ void VulkanDriver::bindDescriptorSet( backend::DescriptorSetOffsetArray&& offsets) { if (dsh) { auto set = resource_ptr::cast(&mResourceManager, dsh); - mDescriptorSetManager.bind(setIndex, set, std::move(offsets)); + mDescriptorSetCache.bind(setIndex, set, std::move(offsets)); } else { - mDescriptorSetManager.unbind(setIndex); + mDescriptorSetCache.unbind(setIndex); } } @@ -1830,7 +1827,7 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins FVK_SYSTRACE_SCOPE(); VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); - mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer, + mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer, mBoundPipeline.pipelineLayout, mBoundPipeline.descriptorSetMask); diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index f488200abe..613e4d5a6c 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -27,8 +27,9 @@ #include "VulkanSamplerCache.h" #include "VulkanStagePool.h" #include "VulkanQueryManager.h" -#include "vulkan/caching/VulkanDescriptorSetManager.h" -#include "vulkan/caching/VulkanPipelineLayoutCache.h" +#include "vulkan/VulkanDescriptorSetCache.h" +#include "vulkan/VulkanDescriptorSetLayoutCache.h" +#include "vulkan/VulkanPipelineLayoutCache.h" #include "vulkan/memory/ResourceManager.h" #include "vulkan/memory/ResourcePointer.h" #include "vulkan/utils/Definitions.h" @@ -137,7 +138,8 @@ private: VulkanSamplerCache mSamplerCache; VulkanBlitter mBlitter; VulkanReadPixels mReadPixels; - VulkanDescriptorSetManager mDescriptorSetManager; + VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache; + VulkanDescriptorSetCache mDescriptorSetCache; VulkanQueryManager mQueryManager; // This is necessary for us to write to push constants after binding a pipeline. diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 9260eaa14a..da5f36b92c 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -15,15 +15,12 @@ */ #include "VulkanPipelineCache.h" -#include "VulkanMemory.h" -#include "caching/VulkanDescriptorSetManager.h" #include #include #include "VulkanConstants.h" #include "VulkanHandles.h" -#include "VulkanTexture.h" #include "vulkan/utils/Conversion.h" #if defined(__clang__) diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp b/filament/backend/src/vulkan/VulkanPipelineLayoutCache.cpp similarity index 100% rename from filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp rename to filament/backend/src/vulkan/VulkanPipelineLayoutCache.cpp diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h b/filament/backend/src/vulkan/VulkanPipelineLayoutCache.h similarity index 98% rename from filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h rename to filament/backend/src/vulkan/VulkanPipelineLayoutCache.h index 212ad60b0c..2f2a241d57 100644 --- a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineLayoutCache.h @@ -17,7 +17,8 @@ #ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H #define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H -#include +#include "VulkanHandles.h" + #include #include diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index 6ad19912c7..87753d1438 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -1000,6 +1000,15 @@ VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chrom return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range, viewType, swizzle); } + +ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const { + return getSwapchainInstanceExtensionsImpl(); +} + +VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow, + VkInstance instance, uint64_t flags) const noexcept { + return createVkSurfaceKHRImpl(nativeWindow, instance, flags); +} #undef SWAPCHAIN_RET_FUNC }// namespace filament::backend diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp index 9cdd3750ec..441004e995 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include +#include #include -#include #include #include "vulkan/VulkanConstants.h" @@ -157,7 +156,7 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, }; - VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + VkImageCreateInfo imageInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; imageInfo.pNext = &externalCreateInfo; imageInfo.format = metadata.format; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -200,14 +199,12 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic return data; } -} // namespace +}// namespace -namespace fvkandroid { +VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default; -ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default; - -Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, - bool sRGB) noexcept { +Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage( + AHardwareBuffer const* buffer, bool sRGB) noexcept { if (__builtin_available(android 26, *)) { AHardwareBuffer_Desc hardwareBufferDescription = {}; AHardwareBuffer_describe(buffer, &hardwareBufferDescription); @@ -226,12 +223,23 @@ Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer, return Platform::ExternalImageHandle{}; } -} // namespace fvkandroid - -VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl( - ExternalImageHandleRef externalImage, VkDevice device) { +VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc( + ExternalImageHandleRef externalImage) const noexcept { auto const* fvkExternalImage = - static_cast(externalImage.get()); + static_cast(externalImage.get()); + + return { + .width = fvkExternalImage->width, + .height = fvkExternalImage->height, + .format = fvkExternalImage->format, + .usage = fvkExternalImage->usage, + }; +} + +VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata( + ExternalImageHandleRef externalImage) { + auto const* fvkExternalImage = + static_cast(externalImage.get()); ExternalImageMetadata metadata; AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer; @@ -245,7 +253,7 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm std::tie(metadata.format, metadata.usage) = getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB); } - + metadata.samples = VK_SAMPLE_COUNT_1_BIT; VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = { @@ -256,11 +264,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID, .pNext = &formatInfo, }; - VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties); + VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(getDevice(), buffer, &properties); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) - << "vkGetAndroidHardwareBufferProperties failed with error=" - << static_cast(result); - + << "vkGetAndroidHardwareBufferProperties failed with error=" + << static_cast(result); + VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB); FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat) << "mismatched image format( " << metadata.format << ") and queried format(" @@ -271,14 +279,14 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm return metadata; } -VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl( - ExternalImageHandleRef externalImage, VkDevice device, - const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) { +VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData( + ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata, + uint32_t memoryTypeIndex, VkImageUsageFlags usage) { auto const* fvkExternalImage = - static_cast(externalImage.get()); - ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata, + static_cast(externalImage.get()); + ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata, memoryTypeIndex, usage); - VkResult result = vkBindImageMemory(device, data.first, data.second, 0); + VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkBindImageMemory error=" << static_cast(result); return data; @@ -397,14 +405,14 @@ VkSampler VulkanPlatform::createExternalSamplerImpl( return sampler; } -VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() { +VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const { return { VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, }; } -VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow, - VkInstance instance, uint64_t flags) noexcept { +VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* nativeWindow, + VkInstance instance, uint64_t flags) const noexcept { VkSurfaceKHR surface; VkExtent2D extent; @@ -416,6 +424,26 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface); FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateAndroidSurfaceKHR with error=" << static_cast(result); - return {surface, extent}; + return { surface, extent }; } + +// Deprecated platform dependent helper methods +VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; } + +VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl( + ExternalImageHandleRef externalImage, VkDevice device) { + return ExternalImageMetadata{}; } + +VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl( + ExternalImageHandleRef externalImage, VkDevice device, + const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) { + return ImageData{}; +} + +VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow, + VkInstance instance, uint64_t flags) noexcept { + return SurfaceBundle{}; +} + +}// namespace filament::backend diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm index 9f28051cfb..c9e354f450 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm +++ b/filament/backend/src/vulkan/platform/VulkanPlatformApple.mm @@ -52,7 +52,7 @@ using namespace bluevk; namespace filament::backend { -VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() { +VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { ExtensionSet const ret = { #if defined(__APPLE__) VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface @@ -87,7 +87,7 @@ VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, return VK_NULL_HANDLE; } -VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow, +VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance, uint64_t flags) noexcept { VkSurfaceKHR surface; #if defined(__APPLE__) diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp index cf2706fc96..d563317014 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformLinuxWindows.cpp @@ -108,7 +108,7 @@ VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, return VK_NULL_HANDLE; } -VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() { +VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { VulkanPlatform::ExtensionSet const ret = { #if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND) VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, @@ -126,7 +126,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() { return ret; } -VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow, +VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance, uint64_t flags) noexcept { VkSurfaceKHR surface; diff --git a/filament/backend/src/webgpu/WebGPUDriver.cpp b/filament/backend/src/webgpu/WebGPUDriver.cpp index c3eaeb7785..88a3a42c69 100644 --- a/filament/backend/src/webgpu/WebGPUDriver.cpp +++ b/filament/backend/src/webgpu/WebGPUDriver.cpp @@ -651,11 +651,11 @@ uint8_t WebGPUDriver::getMaxDrawBuffers() { return MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; } -size_t WebGPUDriver::getMaxUniformBufferSize(SamplerType) { +size_t WebGPUDriver::getMaxUniformBufferSize() { return 16384u; } -size_t WebGPUDriver::getMaxTextureSize() { +size_t WebGPUDriver::getMaxTextureSize(SamplerType target) { return 2048u; } diff --git a/filament/backend/src/webgpu/platform/WebGPUPlatform.cpp b/filament/backend/src/webgpu/platform/WebGPUPlatform.cpp index e83acb0016..51d7d1ebf3 100644 --- a/filament/backend/src/webgpu/platform/WebGPUPlatform.cpp +++ b/filament/backend/src/webgpu/platform/WebGPUPlatform.cpp @@ -143,7 +143,7 @@ wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) { return device; } -Driver* WebGPUPlatform::createDriver(void* const sharedContext, +Driver* WebGPUPlatform::createDriver(void* sharedContext, const Platform::DriverConfig& /*driverConfig*/) noexcept { if (sharedContext) { FWGPU_LOGW << "sharedContext is ignored/unused in the WebGPU backend. A non-null " diff --git a/filament/backend/src/webgpu/platform/WebGPUPlatformLinux.cpp b/filament/backend/src/webgpu/platform/WebGPUPlatformLinux.cpp index 16623891c9..00d1651e26 100644 --- a/filament/backend/src/webgpu/platform/WebGPUPlatformLinux.cpp +++ b/filament/backend/src/webgpu/platform/WebGPUPlatformLinux.cpp @@ -15,6 +15,8 @@ */ #include +#include + #include #include @@ -118,7 +120,9 @@ wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t flags) if (useXcb) { wgpu::SurfaceSourceXCBWindow surfaceSourceXcb{}; surfaceSourceXcb.connection = g_x11.connection; - surfaceSourceXcb.window = reinterpret_cast(nativeWindow); + + // TODO: this looks really wrong, please fix!! + surfaceSourceXcb.window = *((uint32_t*) nativeWindow); wgpu::SurfaceDescriptor surfaceDescriptor{ .nextInChain = &surfaceSourceXcb, .label = "linux_xcb_surface" diff --git a/filament/include/filament/ColorGrading.h b/filament/include/filament/ColorGrading.h index e5c8f3cae3..3e4916fbb2 100644 --- a/filament/include/filament/ColorGrading.h +++ b/filament/include/filament/ColorGrading.h @@ -64,9 +64,8 @@ class ColorSpace; * Performance * =========== * - * Creating a new ColorGrading object may be more expensive than other Filament objects as a - * 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on - * the CPU. + * Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may + * need to be generated. The generation of this LUT, if necessary, may happen on the CPU. * * Ordering * ======== @@ -155,6 +154,9 @@ public: * 3D texture. For instance, a low quality level will use a 16x16x16 10 bit LUT, a medium * quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit * LUT, and a ultra quality will use a 64x64x64 16 bit LUT. + * + * This setting has no effect if generating a 1D LUT. + * * This overrides the values set by format() and dimensions(). * * The default quality is medium. @@ -169,6 +171,8 @@ public: * When color grading is implemented using a 3D LUT, this sets the texture format of * of the LUT. This overrides the value set by quality(). * + * This setting has no effect if generating a 1D LUT. + * * The default is INTEGER * * @param format The desired format of the 3D LUT. @@ -181,6 +185,8 @@ public: * When color grading is implemented using a 3D LUT, this sets the dimension of the LUT. * This overrides the value set by quality(). * + * This setting has no effect if generating a 1D LUT. + * * The default is 32 * * @param dim The desired dimension of the LUT. Between 16 and 64. diff --git a/filament/include/filament/ToneMapper.h b/filament/include/filament/ToneMapper.h index e89e702c99..cff0576eef 100644 --- a/filament/include/filament/ToneMapper.h +++ b/filament/include/filament/ToneMapper.h @@ -68,6 +68,21 @@ struct UTILS_PUBLIC ToneMapper { * function applied ("linear") */ virtual math::float3 operator()(math::float3 c) const noexcept = 0; + + /** + * If true, then this function holds that f(x) = vec3(f(x.r), f(x.g), f(x.b)) + * + * This may be used to indicate that the color grading's LUT only requires a 1D texture instead + * of a 3D texture, potentially saving a significant amount of memory and generation time. + */ + virtual bool isOneDimensional() const noexcept { return false; } + + /** + * True if this tonemapper only works in low-dynamic-range. + * + * This may be used to indicate that the color grading's LUT doesn't need to be log encoded. + */ + virtual bool isLDR() const noexcept { return false; } }; /** @@ -79,6 +94,8 @@ struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper { ~LinearToneMapper() noexcept final; math::float3 operator()(math::float3 c) const noexcept override; + bool isOneDimensional() const noexcept override { return true; } + bool isLDR() const noexcept override { return true; } }; /** @@ -91,6 +108,8 @@ struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper { ~ACESToneMapper() noexcept final; math::float3 operator()(math::float3 c) const noexcept override; + bool isOneDimensional() const noexcept override { return false; } + bool isLDR() const noexcept override { return false; } }; /** @@ -104,6 +123,8 @@ struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper { ~ACESLegacyToneMapper() noexcept final; math::float3 operator()(math::float3 c) const noexcept override; + bool isOneDimensional() const noexcept override { return false; } + bool isLDR() const noexcept override { return false; } }; /** @@ -117,6 +138,8 @@ struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper { ~FilmicToneMapper() noexcept final; math::float3 operator()(math::float3 x) const noexcept override; + bool isOneDimensional() const noexcept override { return true; } + bool isLDR() const noexcept override { return false; } }; /** @@ -129,6 +152,8 @@ struct UTILS_PUBLIC PBRNeutralToneMapper final : public ToneMapper { ~PBRNeutralToneMapper() noexcept final; math::float3 operator()(math::float3 x) const noexcept override; + bool isOneDimensional() const noexcept override { return false; } + bool isLDR() const noexcept override { return false; } }; /** @@ -150,6 +175,8 @@ struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper { ~AgxToneMapper() noexcept final; math::float3 operator()(math::float3 x) const noexcept override; + bool isOneDimensional() const noexcept override { return false; } + bool isLDR() const noexcept override { return false; } AgxLook look; }; @@ -194,6 +221,8 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper { GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept; math::float3 operator()(math::float3 x) const noexcept override; + bool isOneDimensional() const noexcept override { return true; } + bool isLDR() const noexcept override { return false; } /** Returns the contrast of the curve as a strictly positive value. */ float getContrast() const noexcept; @@ -256,6 +285,8 @@ struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper { ~DisplayRangeToneMapper() noexcept override; math::float3 operator()(math::float3 c) const noexcept override; + bool isOneDimensional() const noexcept override { return false; } + bool isLDR() const noexcept override { return false; } }; } // namespace filament diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 469c0122ed..78b78e770a 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -2306,36 +2306,11 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver, const FColorGrading* colorGrading, ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions, uint32_t const width, uint32_t const height) noexcept { - float4 const vignetteParameters = getVignetteParameters(vignetteOptions, width, height); - - auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); - FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(mEngine, material); - - mi->setParameter("lut", colorGrading->getHwHandle(), { - .filterMag = SamplerMagFilter::LINEAR, - .filterMin = SamplerMinFilter::LINEAR, - .wrapS = SamplerWrapMode::CLAMP_TO_EDGE, - .wrapT = SamplerWrapMode::CLAMP_TO_EDGE, - .wrapR = SamplerWrapMode::CLAMP_TO_EDGE, - .anisotropyLog2 = 0 - }); - const float lutDimension = float(colorGrading->getDimension()); - mi->setParameter("lutSize", float2{ - 0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension, - }); - - const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine()); - - mi->setParameter("vignette", vignetteParameters); - mi->setParameter("vignetteColor", vignetteOptions.color); - mi->setParameter("dithering", colorGradingConfig.dithering); - mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance); - mi->setParameter("temporalNoise", temporalNoise); + auto& material = getPostProcessMaterial("colorGradingAsSubpass"); + FMaterialInstance* const mi = + configureColorGradingMaterial(material, colorGrading, colorGradingConfig, + vignetteOptions, width, height); mi->commit(driver); - - // load both variants - material.getMaterial(mEngine, PostProcessVariant::OPAQUE); - material.getMaterial(mEngine, PostProcessVariant::TRANSLUCENT); } void PostProcessManager::colorGradingSubpass(DriverApi& driver, @@ -2487,22 +2462,14 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, auto const& out = resources.getRenderPassInfo(); - auto const& material = getPostProcessMaterial("colorGrading"); - - PostProcessVariant const variant = colorGradingConfig.translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + auto const& input = resources.getDescriptor(data.input); + auto const& output = resources.getDescriptor(data.output); + auto& material = getPostProcessMaterial("colorGrading"); FMaterialInstance* const mi = - PostProcessMaterial::getMaterialInstance(mEngine, material, variant); + configureColorGradingMaterial(material, colorGrading, colorGradingConfig, + vignetteOptions, output.width, output.height); - mi->setParameter("lut", colorGrading->getHwHandle(), { - .filterMag = SamplerMagFilter::LINEAR, - .filterMin = SamplerMinFilter::LINEAR - }); - const float lutDimension = float(colorGrading->getDimension()); - mi->setParameter("lutSize", float2{ - 0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension, - }); mi->setParameter("colorBuffer", colorTexture, { /* shader uses texelFetch */ }); mi->setParameter("bloomBuffer", bloomTexture, { .filterMag = SamplerMagFilter::LINEAR, @@ -2534,19 +2501,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, bloomParameters.y = 1.0f - bloomParameters.x; } - auto const& input = resources.getDescriptor(data.input); - auto const& output = resources.getDescriptor(data.output); - float4 const vignetteParameters = getVignetteParameters( - vignetteOptions, output.width, output.height); - - const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine()); - - mi->setParameter("dithering", colorGradingConfig.dithering); mi->setParameter("bloom", bloomParameters); - mi->setParameter("vignette", vignetteParameters); - mi->setParameter("vignetteColor", vignetteOptions.color); - mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance); - mi->setParameter("temporalNoise", temporalNoise); mi->setParameter("viewport", float4{ float(vp.left) / input.width, float(vp.bottom) / input.height, @@ -2554,7 +2509,9 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, float(vp.height) / input.height }); - commitAndRenderFullScreenQuad(driver, out, mi, variant); + commitAndRenderFullScreenQuad(driver, out, mi, + colorGradingConfig.translucent + ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); } ); @@ -2692,11 +2649,70 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial( setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma); if (dirty) { ma->invalidate(); - // TODO: call Material::compile(), we can't si that now because it works only + // TODO: call Material::compile(), we can't do that now because it works only // with surface materials } } +FMaterialInstance* PostProcessManager::configureColorGradingMaterial( + PostProcessMaterial& material, FColorGrading const* colorGrading, + ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions, + uint32_t const width, uint32_t const height) noexcept { + FMaterial* const ma = material.getMaterial(mEngine); + bool dirty = false; + + auto setConstantParameter = + [&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept { + auto id = material->getSpecializationConstantId(name); + if (id.has_value()) { + if (material->setConstant(id.value(), value)) { + dirty = true; + } + } + }; + + setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional()); + setConstantParameter(ma, "isLDR", colorGrading->isLDR()); + + if (dirty) { + ma->invalidate(); + // TODO: call Material::compile(), we can't do that now because it works only + // with surface materials + } + + PostProcessVariant const variant = colorGradingConfig.translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material, variant); + + const SamplerParams params = { + .filterMag = SamplerMagFilter::LINEAR, + .filterMin = SamplerMinFilter::LINEAR, + .wrapS = SamplerWrapMode::CLAMP_TO_EDGE, + .wrapT = SamplerWrapMode::CLAMP_TO_EDGE, + .wrapR = SamplerWrapMode::CLAMP_TO_EDGE, + .anisotropyLog2 = 0 + }; + + mi->setParameter("lut", colorGrading->getHwHandle(), params); + + const float lutDimension = float(colorGrading->getDimension()); + mi->setParameter("lutSize", float2{ + 0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension, + }); + + const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine()); + + float4 const vignetteParameters = getVignetteParameters(vignetteOptions, width, height); + mi->setParameter("vignette", vignetteParameters); + mi->setParameter("vignetteColor", vignetteOptions.color); + mi->setParameter("dithering", colorGradingConfig.dithering); + mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance); + mi->setParameter("temporalNoise", temporalNoise); + + return mi; +} + FrameGraphId PostProcessManager::taa(FrameGraph& fg, FrameGraphId input, FrameGraphId const depth, diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 677cec30cb..09a6bb52ae 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -401,6 +401,13 @@ public: FMaterialInstance const* mi, PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept; + // Sets the necessary spec constants and uniforms common to both colorGrading.mat and + // colorGradingAsSubpass.mat. + FMaterialInstance* configureColorGradingMaterial( + PostProcessMaterial& material, FColorGrading const* colorGrading, + ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions, + uint32_t const width, uint32_t const height) noexcept; + private: backend::RenderPrimitiveHandle mFullScreenQuadRph; backend::VertexBufferInfoHandle mFullScreenQuadVbih; diff --git a/filament/src/details/ColorGrading.cpp b/filament/src/details/ColorGrading.cpp index a1077f771b..939f0cbbbc 100644 --- a/filament/src/details/ColorGrading.cpp +++ b/filament/src/details/ColorGrading.cpp @@ -35,7 +35,6 @@ #include #include -#include #include namespace filament { @@ -581,8 +580,11 @@ static float3 luminanceScaling(float3 x, // Quality //------------------------------------------------------------------------------ -static std::tuple - selectLutTextureParams(ColorGrading::LutFormat const lutFormat) noexcept { +static std::tuple selectLutTextureParams( + ColorGrading::LutFormat const lutFormat, const bool isOneDimensional) noexcept { + if (isOneDimensional) { + return { TextureFormat::R16F, PixelDataFormat::R, PixelDataType::HALF }; + } // We use RGBA16F for high quality modes instead of RGB16F because RGB16F // is not supported everywhere switch (lutFormat) { @@ -658,27 +660,43 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) { DriverApi& driver = engine.getDriverApi(); - Config c; - // This lock protects the data inside Config, which is written to by the Filament thread, - // and read from multiple Job threads. - Mutex configLock; - { - std::lock_guard const lock(configLock); - c.lutDimension = builder->dimension; - c.adaptationTransform = adaptationTransform(builder->whiteBalance); - c.colorGradingIn = selectColorGradingTransformIn(builder->toneMapping); - c.colorGradingOut = selectColorGradingTransformOut(builder->toneMapping); - c.colorGradingLuminance = selectColorGradingLuminance(builder->toneMapping); - c.oetf = selectOETF(builder->outputColorSpace); + // XXX: The following two conditions also only hold true as long as the input and output color + // spaces are the same, but we currently don't check that. We must revise these conditions if we + // ever handle this case. + mIsOneDimensional = !builder->hasAdjustments && !builder->luminanceScaling + && builder->toneMapper->isOneDimensional(); + mIsLDR = mIsOneDimensional && builder->toneMapper->isLDR(); + + const Config config = { + mIsOneDimensional ? 512u : builder->dimension, + adaptationTransform(builder->whiteBalance), + selectColorGradingTransformIn(builder->toneMapping), + selectColorGradingTransformOut(builder->toneMapping), + selectColorGradingLuminance(builder->toneMapping), + selectOETF(builder->outputColorSpace), + }; + + mDimension = config.lutDimension; + + uint32_t width; + uint32_t height; + uint32_t depth; + if (mIsOneDimensional) { + width = config.lutDimension; + height = 1; + depth = 1; + } else { + width = config.lutDimension; + height = config.lutDimension; + depth = config.lutDimension; } - mDimension = c.lutDimension; - - size_t lutElementCount = c.lutDimension * c.lutDimension * c.lutDimension; - size_t elementSize = sizeof(half4); + size_t lutElementCount = width * height * depth; + size_t elementSize = mIsOneDimensional ? sizeof(half) : sizeof(half4); void* data = malloc(lutElementCount * elementSize); - auto [textureFormat, format, type] = selectLutTextureParams(builder->format); + auto [textureFormat, format, type] = + selectLutTextureParams(builder->format, mIsOneDimensional); assert_invariant(FTexture::isTextureFormatSupported(engine, textureFormat)); assert_invariant(FTexture::validatePixelFormatAndType(textureFormat, format, type)); @@ -688,170 +706,185 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) { converted = malloc(lutElementCount * sizeof(uint32_t)); } + auto hdrColorAt = [builder, config](size_t r, size_t g, size_t b) { + float3 v = float3{r, g, b} * (1.0f / float(config.lutDimension - 1u)); + + // LogC encoding + v = LogC_to_linear(v); + + // Kill negative values near 0.0f due to imprecision in the log conversion + v = max(v, 0.0f); + + if (builder->hasAdjustments) { + // Exposure + v = adjustExposure(v, builder->exposure); + + // Purkinje shift ("low-light" vision) + v = scotopicAdaptation(v, builder->nightAdaptation); + } + + // Move to color grading color space + v = config.colorGradingIn * v; + + if (builder->hasAdjustments) { + // White balance + v = chromaticAdaptation(v, config.adaptationTransform); + + // Kill negative values before the next transforms + v = max(v, 0.0f); + + // Channel mixer + v = channelMixer(v, builder->outRed, builder->outGreen, builder->outBlue); + + // Shadows/mid-tones/highlights + v = tonalRanges(v, config.colorGradingLuminance, + builder->shadows, builder->midtones, builder->highlights, + builder->tonalRanges); + + // The adjustments below behave better in log space + v = linear_to_LogC(v); + + // ASC CDL + v = colorDecisionList(v, builder->slope, builder->offset, builder->power); + + // Contrast in log space + v = contrast(v, builder->contrast); + + // Back to linear space + v = LogC_to_linear(v); + + // Vibrance in linear space + v = vibrance(v, config.colorGradingLuminance, builder->vibrance); + + // Saturation in linear space + v = saturation(v, config.colorGradingLuminance, builder->saturation); + + // Kill negative values before curves + v = max(v, 0.0f); + + // RGB curves + v = curves(v, + builder->shadowGamma, builder->midPoint, builder->highlightScale); + } + + // Tone mapping + if (builder->luminanceScaling) { + v = luminanceScaling(v, *builder->toneMapper, config.colorGradingLuminance); + } else { + v = (*builder->toneMapper)(v); + } + + // Go back to display color space + v = config.colorGradingOut * v; + + // Apply gamut mapping + if (builder->gamutMapping) { + // TODO: This should depend on the output color space + v = gamutMapping_sRGB(v); + } + + // TODO: We should convert to the output color space if we use a working + // color space that's not sRGB + // TODO: Allow the user to customize the output color space + + // We need to clamp for the output transfer function + v = saturate(v); + + // Apply OETF + v = config.oetf(v); + + return v; + }; + //auto now = std::chrono::steady_clock::now(); - // Multithreadedly generate the tone mapping 3D look-up table using 32 jobs - // Slices are 8 KiB (128 cache lines) apart. - // This takes about 3-6ms on Android in Release - JobSystem& js = engine.getJobSystem(); - auto *slices = js.createJob(); - for (size_t b = 0; b < c.lutDimension; b++) { - auto *job = js.createJob(slices, - [data, converted, b, &c, &configLock, builder](JobSystem&, JobSystem::Job*) { - Config config; - { - std::lock_guard lock(configLock); - config = c; + if (mIsOneDimensional) { + half* UTILS_RESTRICT p = (half*) data; + if (mIsLDR) { + for (size_t rgb = 0; rgb < config.lutDimension; rgb++) { + float3 v = float3(rgb) * (1.0f / float(config.lutDimension - 1u)); + + v = (*builder->toneMapper)(float3(v)); + + // We need to clamp for the output transfer function + v = saturate(v); + + // Apply OETF + v = config.oetf(v); + + *p++ = half(v.r); } - half4* UTILS_RESTRICT p = (half4*) data + b * config.lutDimension * config.lutDimension; - for (size_t g = 0; g < config.lutDimension; g++) { - for (size_t r = 0; r < config.lutDimension; r++) { - float3 v = float3{r, g, b} * (1.0f / float(config.lutDimension - 1u)); - - // LogC encoding - v = LogC_to_linear(v); - - // Kill negative values near 0.0f due to imprecision in the log conversion - v = max(v, 0.0f); - - if (builder->hasAdjustments) { - // Exposure - v = adjustExposure(v, builder->exposure); - - // Purkinje shift ("low-light" vision) - v = scotopicAdaptation(v, builder->nightAdaptation); + } else { + for (size_t rgb = 0; rgb < config.lutDimension; rgb++) { + *p++ = half(hdrColorAt(rgb, rgb, rgb).r); + } + } + } else { + // Multithreadedly generate the tone mapping 3D look-up table using 32 jobs + // Slices are 8 KiB (128 cache lines) apart. + // This takes about 3-6ms on Android in Release + JobSystem& js = engine.getJobSystem(); + auto *slices = js.createJob(); + for (size_t b = 0; b < config.lutDimension; b++) { + auto* job = js.createJob(slices, + [data, converted, b, &config, builder, &hdrColorAt]( + JobSystem&, JobSystem::Job*) { + half4* UTILS_RESTRICT p = + (half4*) data + b * config.lutDimension * config.lutDimension; + for (size_t g = 0; g < config.lutDimension; g++) { + for (size_t r = 0; r < config.lutDimension; r++) { + *p++ = half4{hdrColorAt(r, g, b), 0.0f}; } - - // Move to color grading color space - v = c.colorGradingIn * v; - - if (builder->hasAdjustments) { - // White balance - v = chromaticAdaptation(v, config.adaptationTransform); - - // Kill negative values before the next transforms - v = max(v, 0.0f); - - // Channel mixer - v = channelMixer(v, builder->outRed, builder->outGreen, builder->outBlue); - - // Shadows/mid-tones/highlights - v = tonalRanges(v, c.colorGradingLuminance, - builder->shadows, builder->midtones, builder->highlights, - builder->tonalRanges); - - // The adjustments below behave better in log space - v = linear_to_LogC(v); - - // ASC CDL - v = colorDecisionList(v, builder->slope, builder->offset, builder->power); - - // Contrast in log space - v = contrast(v, builder->contrast); - - // Back to linear space - v = LogC_to_linear(v); - - // Vibrance in linear space - v = vibrance(v, c.colorGradingLuminance, builder->vibrance); - - // Saturation in linear space - v = saturation(v, c.colorGradingLuminance, builder->saturation); - - // Kill negative values before curves - v = max(v, 0.0f); - - // RGB curves - v = curves(v, - builder->shadowGamma, builder->midPoint, builder->highlightScale); - } - - // Tone mapping - if (builder->luminanceScaling) { - v = luminanceScaling(v, *builder->toneMapper, c.colorGradingLuminance); - } else { - v = (*builder->toneMapper)(v); - } - - // Go back to display color space - v = c.colorGradingOut * v; - - // Apply gamut mapping - if (builder->gamutMapping) { - // TODO: This should depend on the output color space - v = gamutMapping_sRGB(v); - } - - // TODO: We should convert to the output color space if we use a working - // color space that's not sRGB - // TODO: Allow the user to customize the output color space - - // We need to clamp for the output transfer function - v = saturate(v); - - // Apply OETF - v = c.oetf(v); - - *p++ = half4{v, 0.0f}; } - } - if (converted) { - uint32_t* const UTILS_RESTRICT dst = (uint32_t*) converted + - b * config.lutDimension * config.lutDimension; - half4* UTILS_RESTRICT src = (half4*) data + - b * config.lutDimension * config.lutDimension; - // we use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight - // 32-bits results in one go. - const size_t count = (config.lutDimension * config.lutDimension) & ~0x7u; // tell the compiler that we're a multiple of 8 + if (converted) { + uint32_t* const UTILS_RESTRICT dst = (uint32_t*) converted + + b * config.lutDimension * config.lutDimension; + half4* UTILS_RESTRICT src = (half4*) data + + b * config.lutDimension * config.lutDimension; + // we use a vectorize width of 8 because, on ARMv8 it allows the compiler to + // write eight 32-bits results in one go. + const size_t count = (config.lutDimension * config.lutDimension) & ~0x7u; // tell the compiler that we're a multiple of 8 #if defined(__clang__) - #pragma clang loop vectorize_width(8) +#pragma clang loop vectorize_width(8) #endif - for (size_t i = 0; i < count; ++i) { - float4 v{src[i]}; - uint32_t pr = uint32_t(std::floor(v.x * 1023.0f + 0.5f)); - uint32_t pg = uint32_t(std::floor(v.y * 1023.0f + 0.5f)); - uint32_t pb = uint32_t(std::floor(v.z * 1023.0f + 0.5f)); - dst[i] = (pb << 20u) | (pg << 10u) | pr; + for (size_t i = 0; i < count; ++i) { + float4 v{src[i]}; + uint32_t pr = uint32_t(std::floor(v.x * 1023.0f + 0.5f)); + uint32_t pg = uint32_t(std::floor(v.y * 1023.0f + 0.5f)); + uint32_t pb = uint32_t(std::floor(v.z * 1023.0f + 0.5f)); + dst[i] = (pb << 20u) | (pg << 10u) | pr; + } } - } + }); + js.run(job); + } - }); - js.run(job); + // TODO: Should we do a runAndRetain() and defer the wait() + texture creation until + // getHwHandle() is invoked? + js.runAndWait(slices); } - // TODO: Should we do a runAndRetain() and defer the wait() + texture creation until - // getHwHandle() is invoked? - js.runAndWait(slices); - //std::chrono::duration duration = std::chrono::steady_clock::now() - now; //slog.d << "LUT generation time: " << duration.count() << " ms" << io::endl; - mLutHandle = driver.createTexture( - SamplerType::SAMPLER_3D, - 1, - textureFormat, - 1, - c.lutDimension, - c.lutDimension, - c.lutDimension, - TextureUsage::DEFAULT - ); - if (converted) { free(data); data = converted; elementSize = sizeof(uint32_t); } + // Create texture. + mLutHandle = driver.createTexture(SamplerType::SAMPLER_3D, 1, textureFormat, 1, + width, height, depth, TextureUsage::DEFAULT); + driver.update3DImage(mLutHandle, 0, 0, 0, 0, - c.lutDimension, c.lutDimension, c.lutDimension, + width, height, depth, PixelBufferDescriptor{ - data, lutElementCount * elementSize,format, type, - [](void* buffer, size_t, void*) { free(buffer); } - } - ); + data, lutElementCount * elementSize, format, type, + [](void* buffer, size_t, void*) { free(buffer); } + }); } FColorGrading::~FColorGrading() noexcept = default; diff --git a/filament/src/details/ColorGrading.h b/filament/src/details/ColorGrading.h index e224b5cace..5ac65c129f 100644 --- a/filament/src/details/ColorGrading.h +++ b/filament/src/details/ColorGrading.h @@ -42,12 +42,15 @@ public: void terminate(FEngine& engine); backend::TextureHandle getHwHandle() const noexcept { return mLutHandle; } - uint32_t getDimension() const noexcept { return mDimension; } + bool isOneDimensional() const noexcept { return mIsOneDimensional; } + bool isLDR() const noexcept { return mIsLDR; } private: backend::TextureHandle mLutHandle; uint32_t mDimension; + bool mIsOneDimensional; + bool mIsLDR; }; FILAMENT_DOWNCAST(ColorGrading) diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index e9becb0ec7..8a367a2fd3 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -153,9 +153,10 @@ Texture::Builder& Texture::Builder::name(const char* name, size_t const len) noe } Texture* Texture::Builder::build(Engine& engine) { - FILAMENT_CHECK_PRECONDITION(Texture::isTextureFormatSupported(engine, mImpl->mFormat)) - << "Texture format " << uint16_t(mImpl->mFormat) << " not supported on this platform"; - + if (mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) { + FILAMENT_CHECK_PRECONDITION(Texture::isTextureFormatSupported(engine, mImpl->mFormat)) + << "Texture format " << uint16_t(mImpl->mFormat) << " not supported on this platform"; + } const bool isProtectedTexturesSupported = downcast(engine).getDriverApi().isProtectedTexturesSupported(); const bool useProtectedMemory = bool(mImpl->mUsage & TextureUsage::PROTECTED); diff --git a/filament/src/materials/colorGrading/colorGrading.fs b/filament/src/materials/colorGrading/colorGrading.fs index 2b2000142d..195b3ff749 100644 --- a/filament/src/materials/colorGrading/colorGrading.fs +++ b/filament/src/materials/colorGrading/colorGrading.fs @@ -1,13 +1,29 @@ -vec3 colorGrade(mediump sampler3D lut, const vec3 x) { +vec3 LogC_to_linear(const vec3 x) { // Alexa LogC EI 1000 const float a = 5.555556; const float b = 0.047996; const float c = 0.244161 / log2(10.0); const float d = 0.386036; - vec3 logc = c * log2(a * x + b) + d; + return c * log2(a * x + b) + d; +} - // Remap to sample pixel centers - logc = materialParams.lutSize.x + logc * materialParams.lutSize.y; +vec3 colorGrade3D(mediump sampler3D lut, const vec3 v) { + return textureLod(lut, v, 0.0).rgb; +} - return textureLod(lut, logc, 0.0).rgb; +vec3 colorGrade1D(mediump sampler3D lut, const vec3 v) { + return vec3( + textureLod(lut, vec3(v.r, 0.5, 0.5), 0.0).r, + textureLod(lut, vec3(v.g, 0.5, 0.5), 0.0).r, + textureLod(lut, vec3(v.b, 0.5, 0.5), 0.0).r); +} + +vec3 colorGrade(mediump sampler3D lut, vec3 v) { + if (!materialConstants_isLDR) { + v = LogC_to_linear(v); + } + // Remap to sample pixel centers. + v = materialParams.lutSize.x + v * materialParams.lutSize.y; + return materialConstants_isOneDimensional + ? colorGrade1D(lut, v) : colorGrade3D(lut, v); } diff --git a/filament/src/materials/colorGrading/colorGrading.mat b/filament/src/materials/colorGrading/colorGrading.mat index 20315b5a62..8c14501771 100644 --- a/filament/src/materials/colorGrading/colorGrading.mat +++ b/filament/src/materials/colorGrading/colorGrading.mat @@ -66,6 +66,16 @@ material { precision : high } ], + constants : [ + { + type : bool, + name : isOneDimensional + }, + { + type : bool, + name : isLDR + } + ], variables : [ vertex ], @@ -154,7 +164,7 @@ void postProcess(inout PostProcessInputs postProcess) { } // Color grading - color.rgb = colorGrade(materialParams_lut, color.rgb); + color.rgb = colorGrade(materialParams_lut, color.rgb); // output in premultiplied alpha #if !POST_PROCESS_OPAQUE diff --git a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat index 3d9aa0b799..49992f78ca 100644 --- a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat +++ b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat @@ -32,6 +32,16 @@ material { name : vignetteColor } ], + constants : [ + { + type : bool, + name : isOneDimensional + }, + { + type : bool, + name : isLDR + } + ], subpasses : [ { type : subpassInput, @@ -103,7 +113,7 @@ void postProcess(inout PostProcessInputs postProcess) { } // Color grading - color.rgb = colorGrade(materialParams_lut, color.rgb); + color.rgb = colorGrade(materialParams_lut, color.rgb); // output in premultiplied alpha #if !POST_PROCESS_OPAQUE diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index af2ff75e12..23a0c603c1 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.58.0" + spec.version = "1.58.1" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.0/filament-v1.58.0-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.1/filament-v1.58.1-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/libs/bluegl/CMakeLists.txt b/libs/bluegl/CMakeLists.txt index fa495ec80c..b43a204b96 100644 --- a/libs/bluegl/CMakeLists.txt +++ b/libs/bluegl/CMakeLists.txt @@ -31,13 +31,17 @@ if (WIN32) set(SRCS ${SRCS} src/BlueGLCoreWindowsImpl.S) endif() elseif (APPLE AND NOT IOS) - set(SRCS ${SRCS} src/BlueGLDarwin.cpp) + if (FILAMENT_SUPPORTS_OSMESA) + set(SRCS ${SRCS} src/BlueGLOSMesa.cpp) + else() + set(SRCS ${SRCS} src/BlueGLDarwin.cpp) + endif() set(SRCS ${SRCS} src/BlueGLCoreDarwinUniversalImpl.S) elseif(LINUX) - if(FILAMENT_SUPPORTS_EGL_ON_LINUX) + if (FILAMENT_SUPPORTS_EGL_ON_LINUX) set(SRCS ${SRCS} src/BlueGLLinuxEGL.cpp) - elseif(FILAMENT_SUPPORTS_OSMESA) - set(SRCS ${SRCS} src/BlueGLLinuxOSMesa.cpp) + elseif (FILAMENT_SUPPORTS_OSMESA) + set(SRCS ${SRCS} src/BlueGLOSMesa.cpp) else() set(SRCS ${SRCS} src/BlueGLLinux.cpp) endif() @@ -53,7 +57,11 @@ include_directories(${PUBLIC_HDR_DIR}) add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS}) if(FILAMENT_SUPPORTS_OSMESA) - target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL) + if (APPLE) + target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include) + else() + target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL) + endif() endif() # specify where the public headers of this library are diff --git a/libs/bluegl/src/BlueGLLinuxOSMesa.cpp b/libs/bluegl/src/BlueGLOSMesa.cpp similarity index 78% rename from libs/bluegl/src/BlueGLLinuxOSMesa.cpp rename to libs/bluegl/src/BlueGLOSMesa.cpp index 7b2e4624d4..88ab35ad3a 100644 --- a/libs/bluegl/src/BlueGLLinuxOSMesa.cpp +++ b/libs/bluegl/src/BlueGLOSMesa.cpp @@ -17,42 +17,64 @@ #include #include +#if defined(__linux__) + #include +// This is to ensure that linking during compilation will not fail even if +// OSMesaGetProcAddress is not linked. +__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*); + +#elif defined(__APPLE__) + +#include + +#endif // __linux__ + +#if defined(__linux__) +#endif + namespace bluegl { namespace { using ProcAddressFunc = void*(*)(char const* funcName); } -// This is to ensure that linking during compilation will not fail even if -// OSMesaGetProcAddress is not linked. -__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*); - struct Driver { ProcAddressFunc OSMesaGetProcAddress; void* library; } g_driver = {nullptr, nullptr}; bool initBinder() { - constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + static constexpr char const* libraryNames[] = { +#if defined(__linux__) + "libOSMesa.so", + "libosmesa.so", +#elif defined(__APPLE__) + "libOSMesa.dylib", +#endif + }; for (char const* name: libraryNames) { g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW); if (g_driver.library) { break; } } - if (!g_driver.library) { - // The library has been linked explicitly during compile. - g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress"); - } else { + if (g_driver.library) { + // Linking against a libosmesa.so. g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress"); } - +#if defined(__linux__) + else { + // If Filament was built as a dynamic library. + g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress"); + } if (!g_driver.OSMesaGetProcAddress) { + // If statically linking OSMesa. g_driver.OSMesaGetProcAddress = (ProcAddressFunc) OSMesaGetProcAddress; } +#endif return g_driver.OSMesaGetProcAddress; } diff --git a/libs/fgviewer/README.md b/libs/fgviewer/README.md index 48361f5164..aafa65140a 100644 --- a/libs/fgviewer/README.md +++ b/libs/fgviewer/README.md @@ -12,7 +12,7 @@ ## Capabilities -fgviewer is a library and web application for real-time visualization of the frame graph in Filament. +fgviewer is a library and web application for real-time visualization of the frame graph in Filament. It displays active passes and resource usage, providing insights into the rendering pipeline. ## Setup for Desktop diff --git a/libs/fgviewer/include/fgviewer/FrameGraphInfo.h b/libs/fgviewer/include/fgviewer/FrameGraphInfo.h index d1e3b292df..b44420d0a2 100644 --- a/libs/fgviewer/include/fgviewer/FrameGraphInfo.h +++ b/libs/fgviewer/include/fgviewer/FrameGraphInfo.h @@ -58,7 +58,7 @@ public: utils::CString name; utils::CString value; }; - + Resource(ResourceId id, utils::CString name, std::vector properties); diff --git a/libs/fgviewer/src/ApiHandler.cpp b/libs/fgviewer/src/ApiHandler.cpp index 5f49c3605b..dbfc5a8c67 100644 --- a/libs/fgviewer/src/ApiHandler.cpp +++ b/libs/fgviewer/src/ApiHandler.cpp @@ -17,14 +17,22 @@ #include "ApiHandler.h" +#include <__chrono/duration.h> #include #include #include #include +#include #include +#include +#include +#include +#include +#include + namespace filament::fgviewer { using namespace std::chrono_literals; diff --git a/libs/fgviewer/src/DebugServer.cpp b/libs/fgviewer/src/DebugServer.cpp index a68413bdad..159578ed6e 100644 --- a/libs/fgviewer/src/DebugServer.cpp +++ b/libs/fgviewer/src/DebugServer.cpp @@ -21,36 +21,45 @@ #include -#include -#include #include +#include +#include +#include #include #include -namespace filament::fgviewer { // If set to 0, this serves HTML from a resgen resource. Use 1 only during local development, which // serves files directly from the source code tree. #define SERVE_FROM_SOURCE_TREE 0 #if SERVE_FROM_SOURCE_TREE + namespace { std::string const BASE_URL = "libs/fgviewer/web"; } // anonymous + #else + #include "fgviewer_resources.h" #include namespace { + struct Asset { std::string_view mime; std::string_view data; }; + std::unordered_map ASSET_MAP; + } // anonymous + #endif // SERVE_FROM_SOURCE_TREE +namespace filament::fgviewer { + using namespace utils; std::string_view const DebugServer::kSuccessHeader = diff --git a/libs/fgviewer/src/FrameGraphInfo.cpp b/libs/fgviewer/src/FrameGraphInfo.cpp index 90cca55bc1..a1b02a261f 100644 --- a/libs/fgviewer/src/FrameGraphInfo.cpp +++ b/libs/fgviewer/src/FrameGraphInfo.cpp @@ -16,6 +16,11 @@ #include +#include + +#include +#include + namespace filament::fgviewer { FrameGraphInfo::FrameGraphInfo(utils::CString viewName): diff --git a/libs/fgviewer/src/JsonWriter.cpp b/libs/fgviewer/src/JsonWriter.cpp index 24daab079e..d43c8a4218 100644 --- a/libs/fgviewer/src/JsonWriter.cpp +++ b/libs/fgviewer/src/JsonWriter.cpp @@ -14,11 +14,15 @@ * limitations under the License. */ -#include #include +#include -#include +#include + +#include +#include #include +#include namespace filament::fgviewer { diff --git a/libs/fgviewer/web/app.js b/libs/fgviewer/web/app.js index ccc2c01bb4..071a33e479 100644 --- a/libs/fgviewer/web/app.js +++ b/libs/fgviewer/web/app.js @@ -223,8 +223,8 @@ class FrameGraphSidePanel extends LitElement { return html` ${this.framegraphs.map(({ fgid, name }) => html` -
    ${fgid === this.selectedFrameGraph ? '● ' : ''}${name}
    @@ -440,15 +440,15 @@ class FrameGraphTable extends LitElement { return html` - ${hasSubresources + ${hasSubresources ? html` ${isExpanded ? '▼' : '▶'} - ` + ` : nothing} ${resource.name} - ${hasSubresources && isExpanded ? nothing : html`(${subresourceIds.length})`} + ${hasSubresources && !isExpanded ? html`(${subresourceIds.length})` : nothing} ${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)} @@ -592,12 +592,12 @@ class FrameGraphViewer extends LitElement { return html` - `; diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index f5676640fe..2edbd41a12 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -203,7 +203,7 @@ enum class ReflectionMode : uint8_t { // can't really use std::underlying_type::type because the driver takes a uint32_t using AttributeBitset = utils::bitset32; -static constexpr size_t MATERIAL_PROPERTIES_COUNT = 29; +static constexpr size_t MATERIAL_PROPERTIES_COUNT = 30; enum class Property : uint8_t { BASE_COLOR, //!< float4, all shading models ROUGHNESS, //!< float, lit shading models only @@ -234,6 +234,7 @@ enum class Property : uint8_t { BENT_NORMAL, //!< float3, all shading models only, except unlit SPECULAR_FACTOR, //!< float, lit shading models only, except subsurface and cloth SPECULAR_COLOR_FACTOR, //!< float3, lit shading models only, except subsurface and cloth + SHADOW_STRENGTH, //!< float, [0, 1] strength of shadows received by this material // when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT }; diff --git a/libs/filamat/src/Enums.cpp b/libs/filamat/src/Enums.cpp index bb163425da..cf23a5efb0 100644 --- a/libs/filamat/src/Enums.cpp +++ b/libs/filamat/src/Enums.cpp @@ -49,7 +49,8 @@ std::unordered_map Enums::mStringToProperty = { { "microThickness", Property::MICRO_THICKNESS }, { "bentNormal", Property::BENT_NORMAL }, { "specularFactor", Property::SPECULAR_FACTOR }, - { "specularColorFactor", Property::SPECULAR_COLOR_FACTOR } + { "specularColorFactor", Property::SPECULAR_COLOR_FACTOR }, + { "shadowStrength", Property::SHADOW_STRENGTH } }; template <> diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index c61e384cbc..63a8eec613 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -1218,6 +1218,7 @@ char const* CodeGenerator::getConstantName(MaterialBuilder::Property property) n case Property::BENT_NORMAL: return "BENT_NORMAL"; case Property::SPECULAR_FACTOR: return "SPECULAR_FACTOR"; case Property::SPECULAR_COLOR_FACTOR: return "SPECULAR_COLOR_FACTOR"; + case Property::SHADOW_STRENGTH: return "SHADOW_STRENGTH"; } } diff --git a/libs/filamat/tests/test_filamat.cpp b/libs/filamat/tests/test_filamat.cpp index 4696685cfa..37baf3e820 100644 --- a/libs/filamat/tests/test_filamat.cpp +++ b/libs/filamat/tests/test_filamat.cpp @@ -696,6 +696,25 @@ TEST_F(MaterialCompiler, StaticCodeAnalyzerBentNormal) { EXPECT_TRUE(PropertyListsMatch(expected, properties)); } +TEST_F(MaterialCompiler, StaticCodeAnalyzerShadowStrength) { + std::string fragmentCode(R"( + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.shadowStrength = 0.1; + } + )"); + + std::string shaderCode = shaderWithAllProperties(*jobSystem, ShaderStage::FRAGMENT, + fragmentCode); + + GLSLTools glslTools; + MaterialBuilder::PropertyList properties{ false }; + glslTools.findProperties(ShaderStage::FRAGMENT, shaderCode, properties); + MaterialBuilder::PropertyList expected{ false }; + expected[size_t(filamat::MaterialBuilder::Property::SHADOW_STRENGTH)] = true; + EXPECT_TRUE(PropertyListsMatch(expected, properties)); +} + TEST_F(MaterialCompiler, StaticCodeAnalyzerOutputFactor) { std::string fragmentCode(R"( void material(inout MaterialInputs material) { diff --git a/shaders/src/surface_light_directional.fs b/shaders/src/surface_light_directional.fs index 9ef63c79e8..fe054e0774 100644 --- a/shaders/src/surface_light_directional.fs +++ b/shaders/src/surface_light_directional.fs @@ -58,6 +58,9 @@ void evaluateDirectionalLight(const MaterialInputs material, if (hasDirectionalShadows && cascadeHasVisibleShadows) { highp vec4 shadowPosition = getShadowPosition(cascade); visibility = shadow(true, sampler0_shadowMap, cascade, shadowPosition, 0.0); +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) + applyShadowStrength(visibility, material.shadowStrength); +#endif // shadow far attenuation highp vec3 v = getWorldPosition() - getWorldCameraPosition(); // (viewFromWorld * v).z == dot(transpose(viewFromWorld), v) diff --git a/shaders/src/surface_light_punctual.fs b/shaders/src/surface_light_punctual.fs index a4d1f91257..44c29fb439 100644 --- a/shaders/src/surface_light_punctual.fs +++ b/shaders/src/surface_light_punctual.fs @@ -222,6 +222,9 @@ void evaluatePunctualLights(const MaterialInputs material, highp vec4 shadowPosition = getShadowPosition(shadowIndex, light.direction, light.zLight); visibility = shadow(false, sampler0_shadowMap, shadowIndex, shadowPosition, light.zLight); +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) + applyShadowStrength(visibility, material.shadowStrength); +#endif } if (light.contactShadows && visibility > 0.0) { if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0) { diff --git a/shaders/src/surface_material_inputs.fs b/shaders/src/surface_material_inputs.fs index 32923dc90a..bd59519526 100644 --- a/shaders/src/surface_material_inputs.fs +++ b/shaders/src/surface_material_inputs.fs @@ -98,6 +98,10 @@ struct MaterialInputs { vec3 specularColorFactor; #endif +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) + float shadowStrength; +#endif + }; void initMaterial(out MaterialInputs material) { @@ -195,6 +199,9 @@ void initMaterial(out MaterialInputs material) { material.specularColorFactor = vec3(1.0); #endif +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) + material.shadowStrength = 0.0; +#endif } #if defined(MATERIAL_HAS_CUSTOM_SURFACE_SHADING) diff --git a/shaders/src/surface_shading_unlit.fs b/shaders/src/surface_shading_unlit.fs index a3ff0059c8..88b1bd258e 100644 --- a/shaders/src/surface_shading_unlit.fs +++ b/shaders/src/surface_shading_unlit.fs @@ -47,6 +47,9 @@ vec4 evaluateMaterial(const MaterialInputs material) { if (hasDirectionalShadows && cascadeHasVisibleShadows) { highp vec4 shadowPosition = getShadowPosition(cascade); visibility = shadow(true, sampler0_shadowMap, cascade, shadowPosition, 0.0); +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) + applyShadowStrength(visibility, material.shadowStrength); +#endif // shadow far attenuation highp vec3 v = getWorldPosition() - getWorldCameraPosition(); // (viewFromWorld * v).z == dot(transpose(viewFromWorld), v) diff --git a/shaders/src/surface_shadowing.fs b/shaders/src/surface_shadowing.fs index cde6d8a9ee..f4c8b18c9c 100644 --- a/shaders/src/surface_shadowing.fs +++ b/shaders/src/surface_shadowing.fs @@ -511,6 +511,12 @@ int getPointLightFace(const highp vec3 r) { } } +#if defined(MATERIAL_HAS_SHADOW_STRENGTH) +void applyShadowStrength(inout float visibility, float strength) { + visibility = 1.0 - (1.0 - visibility) * strength; +} +#endif + // PCF sampling float shadow(const bool DIRECTIONAL, const mediump sampler2DArrayShadow shadowMap, diff --git a/test/renderdiff/src/run.py b/test/renderdiff/src/run.py index 9b63ebd4b3..15c5663eba 100644 --- a/test/renderdiff/src/run.py +++ b/test/renderdiff/src/run.py @@ -46,7 +46,12 @@ def render_test(gltf_viewer, test_config, output_dir, for backend in test_config.backends: env = None if backend == 'opengl' and opengl_lib and os.path.isdir(opengl_lib): - env = {'LD_LIBRARY_PATH': opengl_lib} + env = { + 'LD_LIBRARY_PATH': opengl_lib, + + # for macOS + 'DYLD_LIBRARY_PATH': opengl_lib, + } for model in test.models: model_path = test_config.models[model] diff --git a/test/renderdiff/test.sh b/test/renderdiff/test.sh index 7321a468ae..ea8c6399ac 100755 --- a/test/renderdiff/test.sh +++ b/test/renderdiff/test.sh @@ -18,11 +18,19 @@ OUTPUT_DIR="$(pwd)/out/renderdiff_tests" RENDERDIFF_TEST_DIR="$(pwd)/test/renderdiff" TEST_UTILS_DIR="$(pwd)/test/utils" MESA_DIR="$(pwd)/mesa/out/" -MESA_LIB_DIR="${MESA_DIR}/lib/x86_64-linux-gnu" + +os_name=$(uname -s) +if [[ "$os_name" == "Linux" ]]; then + MESA_LIB_DIR="${MESA_DIR}lib/x86_64-linux-gnu" +elif [[ "$os_name" == "Darwin" ]]; then + MESA_LIB_DIR="${MESA_DIR}lib" +else + echo "Unsupported platform for renderdiff tests" + exit 1 +fi function prepare_mesa() { if [ ! -d ${MESA_LIB_DIR} ]; then - rm -rf mesa bash ${TEST_UTILS_DIR}/get_mesa.sh fi } diff --git a/test/renderdiff/tests/presubmit.json b/test/renderdiff/tests/presubmit.json index 761f043fc5..4ddde454c0 100644 --- a/test/renderdiff/tests/presubmit.json +++ b/test/renderdiff/tests/presubmit.json @@ -8,7 +8,8 @@ "models": ["lucy", "DamagedHelmet"], "rendering": { "viewer.cameraFocusDistance": 0, - "view.postProcessingEnabled": true + "view.postProcessingEnabled": true, + "view.dithering": "NONE" } } ], diff --git a/test/utils/get_mesa.sh b/test/utils/get_mesa.sh index 6ecb325d22..d44d0b7103 100755 --- a/test/utils/get_mesa.sh +++ b/test/utils/get_mesa.sh @@ -17,55 +17,109 @@ set -xe # GITHUB_CLANG_VERSION is set in build/linux/ci-common.sh +os_name=$(uname -s) +LLVM_VERSION=16 +MESA_DIR=$(pwd)/mesa -if [[ "$GITHUB_WORKFLOW" ]]; then - # We only want to do this if it is a CI machine. - sudo apt-get -y remove llvm-* +if [[ "$os_name" == "Linux" ]]; then + if [[ "$GITHUB_WORKFLOW" ]]; then + # We only want to do this if it is a CI machine. + sudo apt-get -y remove llvm-* - # We do a manual install of dependencies instead of `apt-get -y build-dep mesa` - # because this allows us to compile an older mesa, and also because build-deps - # is constantly being updated and sometimes not compatible with the current - # linux platform. - # Note that we assume this platform is compatible with ubuntu-22.04 x86_64 - sudo apt-get -y install \ - autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${GITHUB_CLANG_VERSION} llvm-${GITHUB_CLANG_VERSION}-dev llvm-${GITHUB_CLANG_VERSION}-linker-tools llvm-${GITHUB_CLANG_VERSION}-runtime llvm-${GITHUB_CLANG_VERSION}-tools llvm-spirv-${GITHUB_CLANG_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \ - clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev + # We do a manual install of dependencies instead of `apt-get -y build-dep mesa` + # because this allows us to compile an older mesa, and also because build-deps + # is constantly being updated and sometimes not compatible with the current + # linux platform. + # Note that we assume this platform is compatible with ubuntu-22.04 x86_64 + sudo apt-get -y install \ + autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0f:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-linker-tools llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools llvm-spirv-${LLVM_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \ + clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev - sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100 - sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100 + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100 + else + set +e + sudo apt-get -y build-dep mesa + sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-* + set -e + CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }') + GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}} + sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \ + libc++-${GITHUB_CLANG_VERSION}-dev \ + libc++abi-${GITHUB_CLANG_VERSION}-dev \ + llvm-${LLVM_VERSION} \ + llvm-${LLVM_VERSION}-{dev,tools,runtime} + fi # [[ "$GITHUB_WORKFLOW" ]] +elif [[ "$os_name" == "Darwin" ]]; then + if [[ ! "$GITHUB_WORKFLOW" ]]; then + if [ ! command -v brew > /dev/null 2>&1 ]; then + echo "Error: need to install homebrew to continue" + exit 1 + fi + fi + brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence + + NEEDED_PYTHON_DEPS=("mako" "setuptools") + for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do + if ! pip3 show "${cmd}" >/dev/null 2>&1; then + sudo pip3 install ${cmd} + fi + done +fi # [[ "$os_name" == x ]] + +LOCAL_LDFLAGS=${LDFLAGS} +LOCAL_CPPFLAGS=${CPPFLAGS} +LOCAL_PATH=${PATH} +LOCAL_CXX=$(which clang++) +LOCAL_CC=$(which clang) + +CHECKOUT_MESA=false +if [[ -d "${MESA_DIR}" ]]; then + cd ${MESA_DIR} + if ! git fsck --connectivity-only > /dev/null 2>&1; then + echo "git fsck failed for mesa; try redownloading" + CHECKOUT_MESA=true; + fi + cd ..; else - set +e - sudo apt-get -y build-dep mesa - sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-* - set -e - - CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }') - GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}} - - sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \ - libc++-${GITHUB_CLANG_VERSION}-dev \ - libc++abi-${GITHUB_CLANG_VERSION}-dev \ - llvm-${GITHUB_CLANG_VERSION} \ - llvm-${GITHUB_CLANG_VERSION}-{dev,tools,runtime} + CHECKOUT_MESA=true fi +if [[ "$CHECKOUT_MESA" = "true" ]]; then + rm -rf ${MESA_DIR} -export CXX=`which clang++` && export CC=`which clang` - -git clone https://gitlab.freedesktop.org/mesa/mesa.git + #git clone https://gitlab.freedesktop.org/mesa/mesa.git + git clone git://anongit.freedesktop.org/mesa/mesa + # Due to gitlab mesa outage. + if [[ "${MESA_DIR}" != "$(pwd)/mesa" ]]; then + mv mesa ${MESA_DIR} + fi +fi pushd . +cd ${MESA_DIR} -cd mesa - -git checkout mesa-23.2.1 +# Need >= 24 to have llvmpipe for swrast. llvmpipe is needed for GL >= 4.1. +git checkout mesa-24.2.1 mkdir -p out +if [[ "$os_name" == "Darwin" ]]; then + LOCAL_LDFLAGS="-L/opt/homebrew/opt/llvm@${LLVM_VERSION}/lib" + LOCAL_CPPFLAGS="-I/opt/homebrew/opt/llvm@${LLVM_VERSION}/include -I/opt/homebrew/include" + LOCAL_PATH=${PATH}:/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin + + # This is necessary to be able to build vk (lavapipe) on macOS. Doesn't seem like a real dependency. + sed -I '' "s/error('Vulkan drivers require dri3 for X11 support')//g" meson.build +fi + # -Dosmesa=true => builds OSMesa, which is an offscreen GL context # -Dgallium-drivers=swrast => builds GL software rasterizer # -Dvulkan-drivers=swrast => builds VK software rasterizer -meson setup builddir/ -Dprefix="$(pwd)/out" -Dosmesa=true -Dglx=xlib -Dgallium-drivers=swrast -Dvulkan-drivers=swrast -meson install -C builddir/ +# -Dgallium-drivers=llvmpipe is needed for GL >= 4.1 pipe-screen (see src/gallium/auxiliary/target-helpers/inline_sw_helper.h) +CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \ + meson setup --wipe builddir/ -Dprefix="$(pwd)/out" -Dglx=xlib -Dosmesa=true -Dgallium-drivers=llvmpipe,swrast -Dvulkan-drivers=swrast +CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \ + meson install -C builddir/ popd diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 8445d243a7..d739c8380b 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.58.0", + "version": "1.58.1", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",