diff --git a/CMakeLists.txt b/CMakeLists.txt index f9de5b2a5e4b..d561f4346c90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -667,10 +667,6 @@ function(list_licenses OUTPUT MODULES) endfunction() set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/linux/combine-static-libs.sh") -if (WIN32) - set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/windows/combine-static-libs.bat") - set(CMAKE_AR "lib.exe") -endif() # Add a custom command to TARGET that combines the static libraries in DEPS into a single archive. function(combine_static_libs TARGET OUTPUT DEPS) @@ -685,12 +681,22 @@ function(combine_static_libs TARGET OUTPUT DEPS) endif() endforeach() - add_custom_command( - TARGET ${TARGET} POST_BUILD - COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES} - COMMENT "Combining ${target} dependencies into single shared library" - VERBATIM - ) + if (WIN32) + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND lib.exe /nologo /out:temp.lib ${DEPS_FILES} + COMMAND "${CMAKE_COMMAND}" -E rename temp.lib ${OUTPUT} + COMMENT "Combining ${target} dependencies into single shared library" + VERBATIM + ) + else() + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES} + COMMENT "Combining ${target} dependencies into single shared library" + VERBATIM + ) + endif() endfunction() # ================================================================================================== @@ -761,6 +767,7 @@ add_subdirectory(${LIBRARIES}/utils) add_subdirectory(${LIBRARIES}/viewer) add_subdirectory(${FILAMENT}/filament) add_subdirectory(${FILAMENT}/shaders) +add_subdirectory(${EXTERNAL}/abseil/tnt) add_subdirectory(${EXTERNAL}/basisu/tnt) add_subdirectory(${EXTERNAL}/civetweb/tnt) add_subdirectory(${EXTERNAL}/imgui/tnt) diff --git a/README.md b/README.md index 914a1f3dba32..cba88272aab9 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.56.8' + implementation 'com.google.android.filament:filament-android:1.57.0' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.56.8' +pod 'Filament', '~> 1.57.0' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 09643b5d20a4..802f39ef5851 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,11 @@ 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.57.0 + +- matdbg: Add support for debugging ESSL 1.0 shaders +- backend: New platform API to better handle external textures [⚠️ **New Material Version**] + ## v1.56.8 diff --git a/android/gradle.properties b/android/gradle.properties index 6687f3ef9b77..5974551d5124 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.56.8 +VERSION_NAME=1.57.0 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/build/windows/combine-static-libs.bat b/build/windows/combine-static-libs.bat deleted file mode 100644 index 67f13e1d9127..000000000000 --- a/build/windows/combine-static-libs.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -set selfName=%0 - -:: Check that we have at least 3 arguments. -set argC=0 -for %%x in (%*) do Set /A argC+=1 -if %argC% LSS 3 goto :print_help - -set AR_TOOL=%1 -shift -set OUTPUT_PATH=%1 -shift - -set ARCHIVES= -:loop -if [%1]==[] goto :finished -set ARCHIVES=%ARCHIVES% %1 -shift -goto :loop - -:finished - -%AR_TOOL% /nologo /out:%OUTPUT_PATH% %ARCHIVES% || goto :error - -exit /B %ERRORLEVEL% - -:print_help -echo %selfName%. Combine multiple static libraries using an archiver tool. -echo; -echo Usage: -echo %selfName% ^ ^ ^... -echo; -echo Notes: -echo ^ must be a list of absolute paths to static library archives. -echo This script creates a temporary working directory inside the current directory. -exit /B 1 - -:error -exit /B %ERRORLEVEL% diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 9f0364f94eb3..fae6565e6842 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -385,16 +385,16 @@ endforeach() add_custom_command( OUTPUT "${MATERIAL_DIR}/colorGrading.filamat" - DEPENDS ../shaders/src/dithering.fs - DEPENDS ../shaders/src/vignette.fs + DEPENDS ../shaders/src/inline_dithering.fs + DEPENDS ../shaders/src/inline_vignette.fs DEPENDS src/materials/colorGrading/colorGrading.fs APPEND ) add_custom_command( OUTPUT "${MATERIAL_DIR}/colorGradingAsSubpass.filamat" - DEPENDS ../shaders/src/dithering.fs - DEPENDS ../shaders/src/vignette.fs + DEPENDS ../shaders/src/inline_dithering.fs + DEPENDS ../shaders/src/inline_vignette.fs DEPENDS src/materials/colorGrading/colorGrading.fs APPEND ) diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 208aec0ee009..9fc673990b9d 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -185,8 +185,15 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/platform/VulkanPlatform.cpp src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp src/vulkan/platform/VulkanPlatformSwapChainImpl.h - src/vulkan/spirv/VulkanSpirvUtils.cpp - src/vulkan/spirv/VulkanSpirvUtils.h + src/vulkan/utils/Conversion.cpp + src/vulkan/utils/Conversion.h + src/vulkan/utils/Definitions.h + src/vulkan/utils/Helper.h + src/vulkan/utils/Image.h + src/vulkan/utils/Image.cpp + src/vulkan/utils/Spirv.h + src/vulkan/utils/Spirv.cpp + src/vulkan/utils/StaticVector.h src/vulkan/VulkanAsyncHandles.cpp src/vulkan/VulkanAsyncHandles.h src/vulkan/VulkanBlitter.cpp @@ -205,8 +212,6 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/VulkanFboCache.h src/vulkan/VulkanHandles.cpp src/vulkan/VulkanHandles.h - src/vulkan/VulkanImageUtility.cpp - src/vulkan/VulkanImageUtility.h src/vulkan/VulkanMemory.h src/vulkan/VulkanMemory.cpp src/vulkan/VulkanPipelineCache.cpp @@ -221,8 +226,6 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/VulkanReadPixels.h src/vulkan/VulkanTexture.cpp src/vulkan/VulkanTexture.h - src/vulkan/VulkanUtility.cpp - src/vulkan/VulkanUtility.h ) if (LINUX OR WIN32) list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp) diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 2b68ced9c18e..726665e396a9 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1302,7 +1302,7 @@ enum class Workaround : uint16_t { // for some uniform arrays, it's needed to do an initialization to avoid crash on adreno gpu ADRENO_UNIFORM_ARRAY_CRASH, // Workaround a Metal pipeline compilation error with the message: - // "Could not statically determine the target of a texture". See light_indirect.fs + // "Could not statically determine the target of a texture". See surface_light_indirect.fs METAL_STATIC_TEXTURE_TARGET_ERROR, // Adreno drivers sometimes aren't able to blit into a layer of a texture array. DISABLE_BLIT_INTO_TEXTURE_ARRAY, diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index f9adc51a6236..dac38211ad5f 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -25,6 +25,8 @@ #include #include +#include + namespace filament::backend { class Driver; @@ -41,6 +43,50 @@ class UTILS_PUBLIC Platform { struct Fence {}; struct Stream {}; + class ExternalImageHandle; + + class ExternalImage { + friend class ExternalImageHandle; + std::atomic_uint32_t mRefCount{0}; + protected: + virtual ~ExternalImage() noexcept; + }; + + class ExternalImageHandle { + ExternalImage* UTILS_NULLABLE mTarget = nullptr; + static void incref(ExternalImage* UTILS_NULLABLE p) noexcept; + static void decref(ExternalImage* UTILS_NULLABLE p) noexcept; + + public: + ExternalImageHandle() noexcept; + ~ExternalImageHandle() noexcept; + explicit ExternalImageHandle(ExternalImage* UTILS_NULLABLE p) noexcept; + ExternalImageHandle(ExternalImageHandle const& rhs) noexcept; + ExternalImageHandle(ExternalImageHandle&& rhs) noexcept; + ExternalImageHandle& operator=(ExternalImageHandle const& rhs) noexcept; + ExternalImageHandle& operator=(ExternalImageHandle&& rhs) noexcept; + + explicit operator bool() const noexcept { return mTarget != nullptr; } + + ExternalImage* UTILS_NULLABLE get() noexcept { return mTarget; } + ExternalImage const* UTILS_NULLABLE get() const noexcept { return mTarget; } + + ExternalImage* UTILS_NULLABLE operator->() noexcept { return mTarget; } + ExternalImage const* UTILS_NULLABLE operator->() const noexcept { return mTarget; } + + ExternalImage& operator*() noexcept { return *mTarget; } + ExternalImage const& operator*() const noexcept { return *mTarget; } + + void clear() noexcept; + void reset(ExternalImage* UTILS_NULLABLE p) noexcept; + + private: + friend utils::io::ostream& operator<<(utils::io::ostream& out, + ExternalImageHandle const& handle); + }; + + using ExternalImageHandleRef = ExternalImageHandle const&; + /** * The type of technique for stereoscopic rendering. (Note that the materials used will need to * be compatible with the chosen technique.) @@ -98,6 +144,13 @@ class UTILS_PUBLIC Platform { * - PlatformEGLAndroid */ bool assertNativeWindowIsValid = false; + + /** + * The action to take if a Drawable cannot be acquired. If true, the + * frame is aborted instead of panic. This is only supported for: + * - PlatformMetal + */ + bool metalDisablePanicOnDrawableFailure = false; }; Platform() noexcept; @@ -123,7 +176,7 @@ class UTILS_PUBLIC Platform { * * @return nullptr on failure, or a pointer to the newly created driver. */ - virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, + virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, const DriverConfig& driverConfig) noexcept = 0; /** diff --git a/filament/backend/include/backend/platforms/OpenGLPlatform.h b/filament/backend/include/backend/platforms/OpenGLPlatform.h index e00930c98ca1..a64278dab2ba 100644 --- a/filament/backend/include/backend/platforms/OpenGLPlatform.h +++ b/filament/backend/include/backend/platforms/OpenGLPlatform.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -51,12 +52,23 @@ class OpenGLPlatform : public Platform { ~OpenGLPlatform() noexcept override; public: - struct ExternalTexture { - unsigned int target; // GLenum target - unsigned int id; // GLuint id + unsigned int target; // GLenum target + unsigned int id; // GLuint id }; + /** + * Return the OpenGL vendor string of the specified Driver instance. + * @return The GL_VENDOR string + */ + static utils::CString getVendorString(Driver const* UTILS_NONNULL driver); + + /** + * Return the OpenGL vendor string of the specified Driver instance + * @return The GL_RENDERER string + */ + static utils::CString getRendererString(Driver const* UTILS_NONNULL driver); + /** * Called by the driver to destroy the OpenGL context. This should clean up any windows * or buffers from initialization. This is for instance where `eglDestroyContext` would be @@ -324,36 +336,45 @@ class OpenGLPlatform : public Platform { * Destroys an external texture handle and associated data. * @param texture a pointer to the handle to destroy. */ - virtual void destroyExternalImage(ExternalTexture* UTILS_NONNULL texture) noexcept; + virtual void destroyExternalImageTexture(ExternalTexture* UTILS_NONNULL texture) noexcept; // called on the application thread to allow Filament to take ownership of the image /** * Takes ownership of the externalImage. The externalImage parameter depends on the Platform's - * concrete implementation. Ownership is released when destroyExternalImage() is called. + * concrete implementation. Ownership is released when destroyExternalImageTexture() is called. * * WARNING: This is called synchronously from the application thread (NOT the Driver thread) * * @param externalImage A token representing the platform's external image. * @see destroyExternalImage + * @{ */ virtual void retainExternalImage(void* UTILS_NONNULL externalImage) noexcept; + virtual void retainExternalImage(ExternalImageHandleRef externalImage) noexcept; + /** @}*/ + /** * Called to bind the platform-specific externalImage to an ExternalTexture. * ExternalTexture::id is guaranteed to be bound when this method is called and ExternalTexture * is updated with new values for id/target if necessary. * * WARNING: this method is not allowed to change the bound texture, or must restore the previous - * binding upon return. This is to avoid problem with a backend doing state caching. + * binding upon return. This is to avoid a problem with a backend doing state caching. * * @param externalImage The platform-specific external image. * @param texture an in/out pointer to ExternalTexture, id and target can be updated if necessary. * @return true on success, false on error. + * @{ */ virtual bool setExternalImage(void* UTILS_NONNULL externalImage, ExternalTexture* UTILS_NONNULL texture) noexcept; + virtual bool setExternalImage(ExternalImageHandleRef externalImage, + ExternalTexture* UTILS_NONNULL texture) noexcept; + /** @}*/ + /** * The method allows platforms to convert a user-supplied external image object into a new type * (e.g. HardwareBuffer => EGLImage). The default implementation returns source. diff --git a/filament/backend/include/backend/platforms/PlatformCocoaGL.h b/filament/backend/include/backend/platforms/PlatformCocoaGL.h index 97c9c3ce892d..24f7a43c85ef 100644 --- a/filament/backend/include/backend/platforms/PlatformCocoaGL.h +++ b/filament/backend/include/backend/platforms/PlatformCocoaGL.h @@ -17,7 +17,6 @@ #ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H #define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H -#include #include #include @@ -34,12 +33,14 @@ class PlatformCocoaGL : public OpenGLPlatform { PlatformCocoaGL(); ~PlatformCocoaGL() noexcept override; + ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept; + protected: // -------------------------------------------------------------------------------------------- // Platform Interface Driver* createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept override; + const DriverConfig& driverConfig) noexcept override; // Currently returns 0 int getOSVersion() const noexcept override; @@ -59,10 +60,12 @@ class PlatformCocoaGL : public OpenGLPlatform { void destroySwapChain(SwapChain* swapChain) noexcept override; bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; void commit(SwapChain* swapChain) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; void retainExternalImage(void* externalImage) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + void retainExternalImage(ExternalImageHandleRef externalImage) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; private: PlatformCocoaGLImpl* pImpl = nullptr; diff --git a/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h b/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h index e7f1d1ffe44a..0cea5fe1dcf0 100644 --- a/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h +++ b/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h @@ -32,11 +32,13 @@ class PlatformCocoaTouchGL : public OpenGLPlatform { PlatformCocoaTouchGL(); ~PlatformCocoaTouchGL() noexcept override; + ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept; + // -------------------------------------------------------------------------------------------- // Platform Interface Driver* createDriver(void* sharedGLContext, - const Platform::DriverConfig& driverConfig) noexcept override; + const DriverConfig& driverConfig) noexcept override; int getOSVersion() const noexcept final { return 0; } @@ -56,10 +58,12 @@ class PlatformCocoaTouchGL : public OpenGLPlatform { bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; void commit(SwapChain* swapChain) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; void retainExternalImage(void* externalImage) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + void retainExternalImage(ExternalImageHandleRef externalImage) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; private: PlatformCocoaTouchGLImpl* pImpl = nullptr; diff --git a/filament/backend/include/backend/platforms/PlatformEGL.h b/filament/backend/include/backend/platforms/PlatformEGL.h index ef6876536b12..13a813e9e77b 100644 --- a/filament/backend/include/backend/platforms/PlatformEGL.h +++ b/filament/backend/include/backend/platforms/PlatformEGL.h @@ -47,6 +47,11 @@ class PlatformEGL : public OpenGLPlatform { // Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default. virtual bool isOpenGL() const noexcept; + /** + * Creates an ExternalImage from a EGLImageKHR + */ + ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept; + protected: // -------------------------------------------------------------------------------------------- // Helper for EGL configs and attributes parameters @@ -75,8 +80,7 @@ class PlatformEGL : public OpenGLPlatform { * Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation * that supports OpenGL/OpenGL ES. */ - Driver* createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept override; + Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override; /** * This returns zero. This method can be overridden to return something more useful. @@ -118,9 +122,10 @@ class PlatformEGL : public OpenGLPlatform { void destroyFence(Fence* fence) noexcept override; FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; /** * Logs glGetError() to slog.e @@ -188,6 +193,12 @@ class PlatformEGL : public OpenGLPlatform { void initializeGlExtensions() noexcept; + struct ExternalImageEGL : public ExternalImage { + EGLImageKHR eglImage = EGL_NO_IMAGE; + protected: + ~ExternalImageEGL() override; + }; + protected: EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const; diff --git a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h index bc7d0c1f2f2b..b56d30880b77 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h +++ b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h @@ -57,6 +57,11 @@ class PlatformEGLAndroid : public PlatformEGL { 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 @@ -89,6 +94,15 @@ class PlatformEGLAndroid : public PlatformEGL { */ AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; + + struct ExternalImageEGLAndroid : public ExternalImageEGL { + AHardwareBuffer* aHardwareBuffer = nullptr; + bool sRGB = false; + protected: + ~ExternalImageEGLAndroid() override; + }; + protected: bool makeCurrent(ContextType type, SwapChain* drawSwapChain, diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index 1fe164468139..a00d8e13db7f 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -69,6 +69,16 @@ class Driver { virtual ShaderModel getShaderModel() const noexcept = 0; + // The shader language used for shaders for this driver, used to inform matdbg. + // + // For OpenGL, this distinguishes whether the driver's shaders are powered by ESSL1 or ESSL3. + // This information is used by matdbg to display the correct shader code to the web UI and patch + // the correct chunk when rebuilding shaders live. + // + // Metal shaders can either be MSL or Metal libraries, but at time of writing, matdbg can only + // interface with MSL. + virtual ShaderLanguage getShaderLanguage() const noexcept = 0; + // Returns the dispatcher. This is only called once during initialization of the CommandStream, // so it doesn't matter that it's virtual. virtual Dispatcher getDispatcher() const noexcept = 0; diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 6b951da975c5..2f2921e67136 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -126,8 +126,10 @@ * Driver API below... */ +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" +#endif DECL_DRIVER_API_0(tick) @@ -213,6 +215,14 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle, backend::TextureSwizzle, b, backend::TextureSwizzle, a) +DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage2, + backend::SamplerType, target, + backend::TextureFormat, format, + uint32_t, width, + uint32_t, height, + backend::TextureUsage, usage, + backend::Platform::ExternalImageHandleRef, image) + DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage, backend::SamplerType, target, backend::TextureFormat, format, @@ -353,6 +363,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported) DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers) DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize) DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams) +DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image) DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image) DECL_DRIVER_API_SYNCHRONOUS_N(backend::TimerQueryResult, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime) DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround) @@ -533,7 +544,9 @@ DECL_DRIVER_API_N(scissor, Viewport, scissor) +#if defined(__clang__) #pragma clang diagnostic pop +#endif #undef EXPAND diff --git a/filament/backend/include/private/backend/VirtualMachineEnv.h b/filament/backend/include/private/backend/VirtualMachineEnv.h index 692abb31df32..00dfa439e5b1 100644 --- a/filament/backend/include/private/backend/VirtualMachineEnv.h +++ b/filament/backend/include/private/backend/VirtualMachineEnv.h @@ -18,7 +18,7 @@ #define TNT_FILAMENT_DRIVER_ANDROID_VIRTUAL_MACHINE_ENV_H #include -#include +#include #include @@ -26,25 +26,17 @@ namespace filament { class VirtualMachineEnv { public: + // must be called before VirtualMachineEnv::get() from a thread that is attached to the JavaVM static jint JNI_OnLoad(JavaVM* vm) noexcept; - static VirtualMachineEnv& get() noexcept { - // declaring this thread local, will ensure it's destroyed with the calling thread - static thread_local VirtualMachineEnv instance; - return instance; - } + // must be called on backend thread + static VirtualMachineEnv& get() noexcept; - static JNIEnv* getThreadEnvironment() noexcept { - JNIEnv* env; - assert_invariant(sVirtualMachine); - if (sVirtualMachine->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - return nullptr; // this should not happen - } - return env; - } + // can be called from any thread that already has a JniEnv + static JNIEnv* getThreadEnvironment() noexcept; - inline JNIEnv* getEnvironment() noexcept { - assert_invariant(mVirtualMachine); + // must be called from the backend thread + JNIEnv* getEnvironment() noexcept { JNIEnv* env = mJniEnv; if (UTILS_UNLIKELY(!env)) { return getEnvironmentSlow(); @@ -55,20 +47,14 @@ class VirtualMachineEnv { static void handleException(JNIEnv* env) noexcept; private: - VirtualMachineEnv() noexcept : mVirtualMachine(sVirtualMachine) { - // We're not initializing the JVM here -- but we could -- because most of the time - // we don't need the jvm. Instead we do the initialization on first use. This means we could get - // a nasty slow down the very first time, but we'll live with it for now. - } - - ~VirtualMachineEnv() { - if (mVirtualMachine) { - mVirtualMachine->DetachCurrentThread(); - } - } - + explicit VirtualMachineEnv(JavaVM* vm) noexcept; + ~VirtualMachineEnv() noexcept; JNIEnv* getEnvironmentSlow() noexcept; + + static utils::Mutex sLock; static JavaVM* sVirtualMachine; + static JavaVM* getVirtualMachine(); + JNIEnv* mJniEnv = nullptr; JavaVM* mVirtualMachine = nullptr; }; diff --git a/filament/backend/src/Platform.cpp b/filament/backend/src/Platform.cpp index 77c851294174..5618ed6367cd 100644 --- a/filament/backend/src/Platform.cpp +++ b/filament/backend/src/Platform.cpp @@ -16,8 +16,102 @@ #include +#include + +#include +#include + +#include +#include + namespace filament::backend { +void Platform::ExternalImageHandle::incref(ExternalImage* p) noexcept { + if (p) { + // incrementing the ref-count doesn't acquire or release anything + p->mRefCount.fetch_add(1, std::memory_order_relaxed); + } +} + +void Platform::ExternalImageHandle::decref(ExternalImage* p) noexcept { + if (p) { + // When decrementing the ref-count, unless it reaches zero, there is no need to acquire + // data; we need to release all previous writes though so they can be visible to the thread + // that will actually delete the object. + if (p->mRefCount.fetch_sub(1, std::memory_order_release) == 1) { + // if we reach zero, we're about to delete the object, we need to acquire all previous + // writes from other threads (i.e.: the memory from other threads prior to the decref() + // need to be visible now. + std::atomic_thread_fence(std::memory_order_acquire); + delete p; + } + } +} + +Platform::ExternalImageHandle::ExternalImageHandle() noexcept = default; + +Platform::ExternalImageHandle::~ExternalImageHandle() noexcept { + decref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImage* p) noexcept + : mTarget(p) { + incref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle const& rhs) noexcept + : mTarget(rhs.mTarget) { + incref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle&& rhs) noexcept + : mTarget(rhs.mTarget) { + rhs.mTarget = nullptr; +} + +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=( + ExternalImageHandle const& rhs) noexcept { + if (UTILS_LIKELY(this != &rhs)) { + incref(rhs.mTarget); + decref(mTarget); + mTarget = rhs.mTarget; + } + return *this; +} + +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=( + ExternalImageHandle&& rhs) noexcept { + if (UTILS_LIKELY(this != &rhs)) { + decref(mTarget); + mTarget = rhs.mTarget; + rhs.mTarget = nullptr; + } + return *this; +} + +void Platform::ExternalImageHandle::clear() noexcept { + decref(mTarget); + mTarget = nullptr; +} + +void Platform::ExternalImageHandle::reset(ExternalImage* p) noexcept { + incref(p); + decref(mTarget); + mTarget = p; +} + +utils::io::ostream& operator<<(utils::io::ostream& out, + Platform::ExternalImageHandle const& handle) { + out << "ExternalImageHandle{" << handle.mTarget << "}"; + return out; +} + +// -------------------------------------------------------------------------------------------------------------------- + +Platform::ExternalImage::~ExternalImage() noexcept = default; + +// -------------------------------------------------------------------------------------------------------------------- + Platform::Platform() noexcept = default; // this generates the vtable in this translation unit diff --git a/filament/backend/src/VirtualMachineEnv.cpp b/filament/backend/src/VirtualMachineEnv.cpp index c7ff7b179061..7909afc1307c 100644 --- a/filament/backend/src/VirtualMachineEnv.cpp +++ b/filament/backend/src/VirtualMachineEnv.cpp @@ -18,12 +18,28 @@ #include #include +#include +#include #include +#include + namespace filament { -JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; +using namespace utils; + +// This Mutex shouldn't be subject to the Static Initialization Order Fiasco because its initial state is +// a single int initialized to 0. +/* static*/ Mutex VirtualMachineEnv::sLock; +/* static*/ JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; + +UTILS_NOINLINE +JavaVM* VirtualMachineEnv::getVirtualMachine() { + std::lock_guard const lock(sLock); + assert_invariant(sVirtualMachine); + return sVirtualMachine; +} /* * This is typically called by filament_jni.so when it is loaded. If filament_jni.so is not used, @@ -35,33 +51,82 @@ JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; UTILS_PUBLIC UTILS_NOINLINE jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept { - JNIEnv* env = nullptr; - if (UTILS_UNLIKELY(vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK)) { - // this should not happen - return -1; + std::lock_guard const lock(sLock); + if (sVirtualMachine) { + // It doesn't make sense for JNI_OnLoad() to be called more than once + return JNI_VERSION_1_6; } + + // Here we check this VM at least has JNI_VERSION_1_6 + JNIEnv* env = nullptr; + jint const result = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "Couldn't get JniEnv* from the VM, error = " << result; + sVirtualMachine = vm; return JNI_VERSION_1_6; } UTILS_NOINLINE -void VirtualMachineEnv::handleException(JNIEnv* const env) noexcept { - if (UTILS_UNLIKELY(env->ExceptionCheck())) { - env->ExceptionDescribe(); - env->ExceptionClear(); +VirtualMachineEnv& VirtualMachineEnv::get() noexcept { + JavaVM* const vm = getVirtualMachine(); + // declaring this thread local, will ensure it's destroyed with the calling thread + thread_local VirtualMachineEnv instance{ vm }; + return instance; +} + +UTILS_NOINLINE +JNIEnv* VirtualMachineEnv::getThreadEnvironment() noexcept { + JavaVM* const vm = getVirtualMachine(); + JNIEnv* env = nullptr; + jint const result = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "Couldn't get JniEnv* from the VM, error = " << result; + + return env; +} + +VirtualMachineEnv::VirtualMachineEnv(JavaVM* vm) noexcept : mVirtualMachine(vm) { + // We're not initializing the JVM here -- but we could -- because most of the time + // we don't need the jvm. Instead, we do the initialization on first use. This means we could get + // a nasty slow down the very first time, but we'll live with it for now. +} + +VirtualMachineEnv::~VirtualMachineEnv() noexcept { + if (mVirtualMachine) { + mVirtualMachine->DetachCurrentThread(); } } UTILS_NOINLINE JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept { + FILAMENT_CHECK_PRECONDITION(mVirtualMachine) + << "JNI_OnLoad() has not been called"; + #if defined(__ANDROID__) - mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr); + jint const result = mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr); #else - mVirtualMachine->AttachCurrentThread(reinterpret_cast(&mJniEnv), nullptr); + jint const result = mVirtualMachine->AttachCurrentThread(reinterpret_cast(&mJniEnv), nullptr); #endif - assert_invariant(mJniEnv); + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "JavaVM::AttachCurrentThread failed with error " << result; + + FILAMENT_CHECK_POSTCONDITION(mJniEnv) + << "JavaVM::AttachCurrentThread returned a null mJniEnv"; + return mJniEnv; } +UTILS_NOINLINE +void VirtualMachineEnv::handleException(JNIEnv* const env) noexcept { + if (UTILS_UNLIKELY(env->ExceptionCheck())) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + } // namespace filament diff --git a/filament/backend/src/metal/MetalDriver.h b/filament/backend/src/metal/MetalDriver.h index 3c0aa214d835..7bea1119bf30 100644 --- a/filament/backend/src/metal/MetalDriver.h +++ b/filament/backend/src/metal/MetalDriver.h @@ -67,6 +67,7 @@ class MetalDriver final : public DriverBase { MetalContext* mContext; ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; // Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block. void execute(std::function const& fn) noexcept final; diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 246d83dd2067..4f8010ed9395 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -513,6 +513,14 @@ mContext->textures.insert(construct_handle(th, *mContext, src, r, g, b, a)); } +void MetalDriver::createTextureExternalImage2R(Handle th, + backend::SamplerType target, + backend::TextureFormat format, + uint32_t width, uint32_t height, backend::TextureUsage usage, + Platform::ExternalImageHandleRef image) { + // FIXME: implement createTextureExternalImage2R +} + void MetalDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, backend::TextureFormat format, @@ -747,6 +755,10 @@ return alloc_handle(); } +Handle MetalDriver::createTextureExternalImage2S() noexcept { + return alloc_handle(); +} + Handle MetalDriver::createTextureExternalImageS() noexcept { return alloc_handle(); } @@ -947,6 +959,10 @@ #endif } +ShaderLanguage MetalDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::MSL; +} + Handle MetalDriver::createStreamNative(void* stream) { return {}; } @@ -1135,8 +1151,8 @@ math::float2 MetalDriver::getClipSpaceParams() { // virtual and physical z-coordinate of clip-space is in [-w, 0] - // Note: this is actually never used (see: main.vs), but it's a backend API so we implement it - // properly. + // Note: this is actually never used (see: surface_main.vs), but it's a backend API so we + // implement it properly. return math::float2{ 1.0f, 0.0f }; } @@ -1214,6 +1230,10 @@ th.getId(), level, xoffset, yoffset, zoffset, width, height, depth); } +void MetalDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { + // FIXME: implement setupExternalImage2 +} + void MetalDriver::setupExternalImage(void* image) { // setupExternalImage is called on the Filament thread when creating a Texture or SwapChain from // a CVPixelBuffer external image. Here we take ownership of the passed in buffer by calling diff --git a/filament/backend/src/metal/PlatformMetal.mm b/filament/backend/src/metal/PlatformMetal.mm index e446698b083f..dbc2302b7f3b 100644 --- a/filament/backend/src/metal/PlatformMetal.mm +++ b/filament/backend/src/metal/PlatformMetal.mm @@ -44,6 +44,9 @@ } Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept { + pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure + ? DrawableFailureBehavior::ABORT_FRAME + : DrawableFailureBehavior::PANIC; return MetalDriverFactory::create(this, driverConfig); } diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index af3ad70fbb69..fe37a18bfd13 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -14,9 +14,16 @@ * limitations under the License. */ +#include +#include + #include "noop/NoopDriver.h" #include "CommandStreamDispatcher.h" +#include + +#include + namespace filament::backend { Driver* NoopDriver::create() { @@ -39,6 +46,10 @@ ShaderModel NoopDriver::getShaderModel() const noexcept { #endif } +ShaderLanguage NoopDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::ESSL3; +} + // explicit instantiation of the Dispatcher template class ConcreteDispatcher; @@ -258,6 +269,9 @@ void NoopDriver::update3DImage(Handle th, scheduleDestroy(std::move(data)); } +void NoopDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { +} + void NoopDriver::setupExternalImage(void* image) { } diff --git a/filament/backend/src/noop/NoopDriver.h b/filament/backend/src/noop/NoopDriver.h index 5b4037f657ed..8b522304cc80 100644 --- a/filament/backend/src/noop/NoopDriver.h +++ b/filament/backend/src/noop/NoopDriver.h @@ -34,6 +34,7 @@ class NoopDriver final : public DriverBase { private: ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; uint64_t nextFakeHandle = 1; diff --git a/filament/backend/src/opengl/GLUtils.h b/filament/backend/src/opengl/GLUtils.h index dc9df7871a71..6559148a1e26 100644 --- a/filament/backend/src/opengl/GLUtils.h +++ b/filament/backend/src/opengl/GLUtils.h @@ -18,6 +18,7 @@ #define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H #include +#include #include #include @@ -25,6 +26,8 @@ #include #include +#include +#include #include #include "gl_headers.h" @@ -50,7 +53,7 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* # define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); } #endif -constexpr inline GLuint getComponentCount(ElementType type) noexcept { +constexpr GLuint getComponentCount(ElementType type) noexcept { using ElementType = ElementType; switch (type) { case ElementType::BYTE: @@ -90,7 +93,7 @@ constexpr inline GLuint getComponentCount(ElementType type) noexcept { // Our enums to GLenum conversions // ------------------------------------------------------------------------------------------------ -constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept { +constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept { GLbitfield mask = 0; if (any(flags & TargetBufferFlags::COLOR_ALL)) { mask |= (GLbitfield)GL_COLOR_BUFFER_BIT; @@ -104,7 +107,7 @@ constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexc return mask; } -constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept { +constexpr GLenum getBufferUsage(BufferUsage usage) noexcept { switch (usage) { case BufferUsage::STATIC: return GL_STATIC_DRAW; @@ -113,7 +116,7 @@ constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept { } } -constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept { +constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept { switch (bindingType) { case BufferObjectBinding::VERTEX: return GL_ARRAY_BUFFER; @@ -134,11 +137,11 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no } } -constexpr inline GLboolean getNormalization(bool normalized) noexcept { +constexpr GLboolean getNormalization(bool normalized) noexcept { return GLboolean(normalized ? GL_TRUE : GL_FALSE); } -constexpr inline GLenum getComponentType(ElementType type) noexcept { +constexpr GLenum getComponentType(ElementType type) noexcept { using ElementType = ElementType; switch (type) { case ElementType::BYTE: @@ -183,12 +186,30 @@ constexpr inline GLenum getComponentType(ElementType type) noexcept { } } -constexpr inline GLenum getCubemapTarget(uint16_t layer) noexcept { +constexpr GLenum getTextureTargetNotExternal(SamplerType target) noexcept { + switch (target) { + case SamplerType::SAMPLER_2D: + return GL_TEXTURE_2D; + case SamplerType::SAMPLER_3D: + return GL_TEXTURE_3D; + case SamplerType::SAMPLER_2D_ARRAY: + return GL_TEXTURE_2D_ARRAY; + case SamplerType::SAMPLER_CUBEMAP: + return GL_TEXTURE_CUBE_MAP; + case SamplerType::SAMPLER_CUBEMAP_ARRAY: + return GL_TEXTURE_CUBE_MAP_ARRAY; + case SamplerType::SAMPLER_EXTERNAL: + // we should never be here + return GL_TEXTURE_2D; + } +} + +constexpr GLenum getCubemapTarget(uint16_t layer) noexcept { assert_invariant(layer <= 5); return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; } -constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept { +constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept { using SamplerWrapMode = SamplerWrapMode; switch (mode) { case SamplerWrapMode::REPEAT: @@ -200,7 +221,7 @@ constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept { } } -constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept { +constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept { using SamplerMinFilter = SamplerMinFilter; switch (filter) { case SamplerMinFilter::NEAREST: @@ -215,12 +236,12 @@ constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept { } } -constexpr inline GLenum getTextureFilter(SamplerMagFilter filter) noexcept { +constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept { return GL_NEAREST + GLenum(filter); } -constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept { +constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept { using BlendEquation = BlendEquation; switch (mode) { case BlendEquation::ADD: return GL_FUNC_ADD; @@ -231,7 +252,7 @@ constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept { } } -constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept { +constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept { using BlendFunction = BlendFunction; switch (mode) { case BlendFunction::ZERO: return GL_ZERO; @@ -248,7 +269,7 @@ constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept { } } -constexpr inline GLenum getCompareFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept { switch (func) { case SamplerCompareFunc::LE: return GL_LEQUAL; case SamplerCompareFunc::GE: return GL_GEQUAL; @@ -262,25 +283,25 @@ constexpr inline GLenum getCompareFunc(SamplerCompareFunc func) noexcept { } #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 -constexpr inline GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept { +constexpr GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept { return mode == SamplerCompareMode::NONE ? GL_NONE : GL_COMPARE_REF_TO_TEXTURE; } -constexpr inline GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } #endif -constexpr inline GLenum getDepthFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getDepthFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } -constexpr inline GLenum getStencilFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getStencilFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } -constexpr inline GLenum getStencilOp(StencilOperation op) noexcept { +constexpr GLenum getStencilOp(StencilOperation op) noexcept { switch (op) { case StencilOperation::KEEP: return GL_KEEP; case StencilOperation::ZERO: return GL_ZERO; @@ -293,7 +314,7 @@ constexpr inline GLenum getStencilOp(StencilOperation op) noexcept { } } -constexpr inline GLenum getFormat(PixelDataFormat format) noexcept { +constexpr GLenum getFormat(PixelDataFormat format) noexcept { using PixelDataFormat = PixelDataFormat; switch (format) { case PixelDataFormat::RGB: return GL_RGB; @@ -317,7 +338,7 @@ constexpr inline GLenum getFormat(PixelDataFormat format) noexcept { } } -constexpr inline GLenum getType(PixelDataType type) noexcept { +constexpr GLenum getType(PixelDataType type) noexcept { using PixelDataType = PixelDataType; switch (type) { case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE; @@ -342,7 +363,7 @@ constexpr inline GLenum getType(PixelDataType type) noexcept { } #if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2) -constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept { +constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept { using TextureSwizzle = TextureSwizzle; switch (c) { case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO; @@ -355,7 +376,7 @@ constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept { } #endif -constexpr inline GLenum getCullingMode(CullingMode mode) noexcept { +constexpr GLenum getCullingMode(CullingMode mode) noexcept { switch (mode) { case CullingMode::NONE: // should never happen @@ -370,7 +391,7 @@ constexpr inline GLenum getCullingMode(CullingMode mode) noexcept { } // ES2 supported internal formats for texturing and how they map to a format/type -constexpr inline std::pair textureFormatToFormatAndType( +constexpr std::pair textureFormatToFormatAndType( TextureFormat format) noexcept { switch (format) { case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE }; diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 736fa0d6769b..3390b7f81e0e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -75,9 +75,11 @@ #include #endif +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" +#endif // We can only support this feature on OpenGL ES 3.1+ // Support is currently disabled as we don't need it @@ -152,7 +154,7 @@ using namespace GLUtils; // ------------------------------------------------------------------------------------------------ UTILS_NOINLINE -Driver* OpenGLDriver::create(OpenGLPlatform* const platform, +OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform, void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { assert_invariant(platform); OpenGLPlatform* const ec = platform; @@ -349,6 +351,10 @@ ShaderModel OpenGLDriver::getShaderModel() const noexcept { return mContext.getShaderModel(); } +ShaderLanguage OpenGLDriver::getShaderLanguage() const noexcept { + return mContext.isES2() ? ShaderLanguage::ESSL1 : ShaderLanguage::ESSL3; +} + // ------------------------------------------------------------------------------------------------ // Change and track GL state // ------------------------------------------------------------------------------------------------ @@ -576,6 +582,10 @@ Handle OpenGLDriver::createTextureViewSwizzleS() noexcept { return initHandle(); } +Handle OpenGLDriver::createTextureExternalImage2S() noexcept { + return initHandle(); +} + Handle OpenGLDriver::createTextureExternalImageS() noexcept { return initHandle(); } @@ -897,25 +907,7 @@ void OpenGLDriver::createTextureR(Handle th, SamplerType target, uint t->gl.internalFormat = internalFormat; - switch (target) { - case SamplerType::SAMPLER_EXTERNAL: - // we can't be here -- doesn't matter what we do - case SamplerType::SAMPLER_2D: - t->gl.target = GL_TEXTURE_2D; - break; - case SamplerType::SAMPLER_3D: - t->gl.target = GL_TEXTURE_3D; - break; - case SamplerType::SAMPLER_2D_ARRAY: - t->gl.target = GL_TEXTURE_2D_ARRAY; - break; - case SamplerType::SAMPLER_CUBEMAP: - t->gl.target = GL_TEXTURE_CUBE_MAP; - break; - case SamplerType::SAMPLER_CUBEMAP_ARRAY: - t->gl.target = GL_TEXTURE_CUBE_MAP_ARRAY; - break; - } + t->gl.target = getTextureTargetNotExternal(target); if (t->samples > 1) { // Note: we can't be here in practice because filament's user API doesn't @@ -989,8 +981,7 @@ void OpenGLDriver::createTextureViewR(Handle th, } void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle srch, - backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, - backend::TextureSwizzle a) { + TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) { DEBUG_MARKER() GLTexture const* const src = handle_cast(srch); @@ -1052,6 +1043,57 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle th, SamplerType target, + TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, + Platform::ExternalImageHandleRef image) { + DEBUG_MARKER() + + usage |= TextureUsage::SAMPLEABLE; + usage &= ~TextureUsage::UPLOADABLE; + + auto& gl = mContext; + GLenum internalFormat = getInternalFormat(format); + if (UTILS_UNLIKELY(gl.isES2())) { + // on ES2, format and internal format must match + // FIXME: handle compressed texture format + internalFormat = textureFormatToFormatAndType(format).first; + } + assert_invariant(internalFormat); + + GLTexture* const t = construct(th, target, 1, 1, width, height, 1, format, usage); + assert_invariant(t); + + t->externalTexture = mPlatform.createExternalImageTexture(); + if (t->externalTexture) { + if (target == SamplerType::SAMPLER_EXTERNAL) { + if (UTILS_LIKELY(gl.ext.OES_EGL_image_external_essl3)) { + t->externalTexture->target = GL_TEXTURE_EXTERNAL_OES; + } else { + // revert to texture 2D if external is not supported; what else can we do? + t->externalTexture->target = GL_TEXTURE_2D; + } + } else { + t->externalTexture->target = getTextureTargetNotExternal(target); + } + + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + // internalFormat actually depends on the external image, but it doesn't matter + // because it's not used anywhere for anything important. + t->gl.internalFormat = internalFormat; + t->gl.baseLevel = 0; + t->gl.maxLevel = 0; + t->gl.external = true; // forces bindTexture() call (they're never cached) + } + + bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); + if (mPlatform.setExternalImage(image, t->externalTexture)) { + // the target and id can be reset each time + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + } +} + void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType target, TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) { DEBUG_MARKER() @@ -1073,6 +1115,16 @@ void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType t->externalTexture = mPlatform.createExternalImageTexture(); if (t->externalTexture) { + if (target == SamplerType::SAMPLER_EXTERNAL) { + if (UTILS_LIKELY(gl.ext.OES_EGL_image_external_essl3)) { + t->externalTexture->target = GL_TEXTURE_EXTERNAL_OES; + } else { + // revert to texture 2D if external is not supported; what else can we do? + t->externalTexture->target = GL_TEXTURE_2D; + } + } else { + t->externalTexture->target = getTextureTargetNotExternal(target); + } t->gl.target = t->externalTexture->target; t->gl.id = t->externalTexture->id; // internalFormat actually depends on the external image, but it doesn't matter @@ -1864,7 +1916,7 @@ void OpenGLDriver::destroyTexture(Handle th) { detachStream(t); } if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) { - mPlatform.destroyExternalImage(t->externalTexture); + mPlatform.destroyExternalImageTexture(t->externalTexture); } else { glDeleteTextures(1, &t->gl.id); } @@ -2803,6 +2855,10 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, CHECK_GL_ERROR(utils::slog.e) } +void OpenGLDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { + mPlatform.retainExternalImage(image); +} + void OpenGLDriver::setupExternalImage(void* image) { mPlatform.retainExternalImage(image); } @@ -4090,4 +4146,6 @@ template class ConcreteDispatcher; } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 29ea32c776d1..30ff4213e7c5 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -19,6 +19,7 @@ #include "DriverBase.h" #include "OpenGLContext.h" +#include "OpenGLDriverBase.h" #include "OpenGLTimerQuery.h" #include "GLBufferObject.h" #include "GLDescriptorSet.h" @@ -26,11 +27,10 @@ #include "GLTexture.h" #include "ShaderCompilerService.h" -#include - #include #include #include +#include #include #include #include @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -74,14 +75,14 @@ class OpenGLProgram; class TimerQueryFactoryInterface; struct PushConstantBundle; -class OpenGLDriver final : public DriverBase { +class OpenGLDriver final : public OpenGLDriverBase { inline explicit OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept; - ~OpenGLDriver() noexcept final; - Dispatcher getDispatcher() const noexcept final; + ~OpenGLDriver() noexcept override; + Dispatcher getDispatcher() const noexcept override; public: - static Driver* create(OpenGLPlatform* platform, void* sharedGLContext, + static OpenGLDriver* create(OpenGLPlatform* platform, void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept; class DebugMarker { @@ -184,7 +185,7 @@ class OpenGLDriver final : public DriverBase { std::condition_variable cond; FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED }; }; - std::shared_ptr state{ std::make_shared() }; + std::shared_ptr state{ std::make_shared() }; }; OpenGLDriver(OpenGLDriver const&) = delete; @@ -203,12 +204,21 @@ class OpenGLDriver final : public DriverBase { return mShaderCompilerService; } - ShaderModel getShaderModel() const noexcept final; + ShaderModel getShaderModel() const noexcept override; + ShaderLanguage getShaderLanguage() const noexcept override; /* - * Driver interface + * OpenGLDriver interface */ + utils::CString getVendorString() const noexcept override { + return utils::CString{ mContext.state.vendor }; + } + + utils::CString getRendererString() const noexcept override { + return utils::CString{ mContext.state.renderer }; + } + template friend class ConcreteDispatcher; @@ -235,21 +245,21 @@ class OpenGLDriver final : public DriverBase { } template - typename std::enable_if::value, D>::type* + std::enable_if_t, D>* construct(Handle const& handle, ARGS&& ... args) { return mHandleAllocator.destroyAndConstruct(handle, std::forward(args) ...); } template::value, D>::type> + typename = std::enable_if_t, D>> void destruct(Handle& handle, D const* p) noexcept { return mHandleAllocator.deallocate(handle, p); } template - typename std::enable_if_t< + std::enable_if_t< std::is_pointer_v && - std::is_base_of_v>, Dp> + std::is_base_of_v>, Dp> handle_cast(Handle& handle) { return mHandleAllocator.handle_cast(handle); } @@ -260,9 +270,9 @@ class OpenGLDriver final : public DriverBase { } template - inline typename std::enable_if_t< + std::enable_if_t< std::is_pointer_v && - std::is_base_of_v>, Dp> + std::is_base_of_v>, Dp> handle_cast(Handle const& handle) { return mHandleAllocator.handle_cast(handle); } @@ -302,7 +312,7 @@ class OpenGLDriver final : public DriverBase { void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width, uint32_t height, uint8_t samples) const noexcept; - void textureStorage(OpenGLDriver::GLTexture* t, uint32_t width, uint32_t height, + void textureStorage(GLTexture* t, uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept; /* State tracking GL wrappers... */ @@ -334,7 +344,7 @@ class OpenGLDriver final : public DriverBase { void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept; struct { - backend::DescriptorSetHandle dsh; + DescriptorSetHandle dsh; std::array offsets; } mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT]; diff --git a/filament/backend/src/opengl/OpenGLDriverBase.h b/filament/backend/src/opengl/OpenGLDriverBase.h new file mode 100644 index 000000000000..6fea8f76ce65 --- /dev/null +++ b/filament/backend/src/opengl/OpenGLDriverBase.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H + +#include "DriverBase.h" + +#include + +namespace filament::backend { + +class OpenGLDriverBase : public DriverBase { +protected: + ~OpenGLDriverBase() override; + +public: + virtual utils::CString getVendorString() const noexcept = 0; + virtual utils::CString getRendererString() const noexcept = 0; +}; + +} // filament::backend + +#endif //TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H diff --git a/filament/backend/src/opengl/OpenGLPlatform.cpp b/filament/backend/src/opengl/OpenGLPlatform.cpp index 94c3b991126a..57d021cf0d85 100644 --- a/filament/backend/src/opengl/OpenGLPlatform.cpp +++ b/filament/backend/src/opengl/OpenGLPlatform.cpp @@ -16,6 +16,7 @@ #include +#include "OpenGLDriverBase.h" #include "OpenGLDriverFactory.h" #include @@ -23,21 +24,45 @@ #include #include - +#include +#include #include + #include #include #include +#include "OpenGLDriver.h" + namespace filament::backend { +OpenGLDriverBase::~OpenGLDriverBase() = default; + Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform, - void* sharedContext, const Platform::DriverConfig& driverConfig) { + void* sharedContext, const DriverConfig& driverConfig) { return OpenGLDriverFactory::create(platform, sharedContext, driverConfig); } OpenGLPlatform::~OpenGLPlatform() noexcept = default; +utils::CString OpenGLPlatform::getVendorString(Driver const* driver) { + auto const p = static_cast(driver); +#if UTILS_HAS_RTTI + FILAMENT_CHECK_POSTCONDITION(dynamic_cast(driver)) + << "Driver* has not been allocated with OpenGLPlatform"; +#endif + return p->getVendorString(); +} + +utils::CString OpenGLPlatform::getRendererString(Driver const* driver) { + auto const p = static_cast(driver); +#if UTILS_HAS_RTTI + FILAMENT_CHECK_POSTCONDITION(dynamic_cast(driver)) + << "Driver* has not been allocated with OpenGLPlatform"; +#endif + return p->getRendererString(); +} + void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain, utils::Invocable, utils::Invocable) noexcept { makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain); @@ -121,14 +146,24 @@ OpenGLPlatform::ExternalTexture* OpenGLPlatform::createExternalImageTexture() no return nullptr; } -void OpenGLPlatform::destroyExternalImage( +void OpenGLPlatform::destroyExternalImageTexture( UTILS_UNUSED ExternalTexture* texture) noexcept { } +void OpenGLPlatform::retainExternalImage( + UTILS_UNUSED ExternalImageHandleRef externalImage) noexcept { +} + void OpenGLPlatform::retainExternalImage( UTILS_UNUSED void* externalImage) noexcept { } +bool OpenGLPlatform::setExternalImage( + UTILS_UNUSED ExternalImageHandleRef externalImage, + UTILS_UNUSED ExternalTexture* texture) noexcept { + return false; +} + bool OpenGLPlatform::setExternalImage( UTILS_UNUSED void* externalImage, UTILS_UNUSED ExternalTexture* texture) noexcept { diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp index 9a37198b3b78..88b929d8bb0d 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp @@ -16,13 +16,28 @@ #include "ExternalStreamManagerAndroid.h" -#include +#include + +#include + #include +#include #include +#include + +#if __has_include() +# include +# include +#else +struct ASurfaceTexture; +typedef struct ASurfaceTexture ASurfaceTexture; +#endif -#include +#include -#include +#include + +#include using namespace utils; @@ -32,13 +47,8 @@ using namespace backend; using Stream = Platform::Stream; -template -static void loadSymbol(T*& pfn, const char *symbol) noexcept { - pfn = (T*)dlsym(RTLD_DEFAULT, symbol); -} - ExternalStreamManagerAndroid& ExternalStreamManagerAndroid::create() noexcept { - return *(new ExternalStreamManagerAndroid{}); + return *(new(std::nothrow) ExternalStreamManagerAndroid{}); } void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExternalStreamManagerAndroid) noexcept { @@ -56,23 +66,13 @@ ExternalStreamManagerAndroid::~ExternalStreamManagerAndroid() noexcept = default UTILS_NOINLINE JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept { - JNIEnv * env = mVm.getEnvironment(); + JNIEnv* const env = mVm.getEnvironment(); mJniEnv = env; - jclass SurfaceTextureClass = env->FindClass("android/graphics/SurfaceTexture"); - - mSurfaceTextureClass_updateTexImage = env->GetMethodID( - SurfaceTextureClass, "updateTexImage", "()V"); - - mSurfaceTextureClass_attachToGLContext = env->GetMethodID( - SurfaceTextureClass, "attachToGLContext", "(I)V"); - - mSurfaceTextureClass_detachFromGLContext = env->GetMethodID( - SurfaceTextureClass, "detachFromGLContext", "()V"); - - mSurfaceTextureClass_getTimestamp = env->GetMethodID( - SurfaceTextureClass, "getTimestamp", "()J"); - + mSurfaceTextureClass_updateTexImage = env->GetMethodID(SurfaceTextureClass, "updateTexImage", "()V"); + mSurfaceTextureClass_attachToGLContext = env->GetMethodID(SurfaceTextureClass, "attachToGLContext", "(I)V"); + mSurfaceTextureClass_detachFromGLContext = env->GetMethodID(SurfaceTextureClass, "detachFromGLContext", "()V"); + mSurfaceTextureClass_getTimestamp = env->GetMethodID(SurfaceTextureClass, "getTimestamp", "()J"); return env; } @@ -82,7 +82,7 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept { if (!env) { return nullptr; // this should not happen } - EGLStream* stream = new EGLStream(); + EGLStream* stream = new(std::nothrow) EGLStream(); stream->jSurfaceTexture = env->NewGlobalRef(surfaceTexture); if (__builtin_available(android 28, *)) { stream->nSurfaceTexture = ASurfaceTexture_fromSurfaceTexture(env, surfaceTexture); @@ -91,29 +91,30 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept { } void ExternalStreamManagerAndroid::release(Stream* handle) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { ASurfaceTexture_release(stream->nSurfaceTexture); } - JNIEnv* const env = getEnvironment(); + // use VirtualMachineEnv::getEnvironment() directly because we don't need to cache JNI methods here + JNIEnv* const env = mVm.getEnvironment(); assert_invariant(env); // we should have called attach() by now env->DeleteGlobalRef(stream->jSurfaceTexture); delete stream; } void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { // associate our GL texture to the SurfaceTexture ASurfaceTexture* const aSurfaceTexture = stream->nSurfaceTexture; - if (UTILS_UNLIKELY(ASurfaceTexture_attachToGLContext(aSurfaceTexture, (uint32_t)tname))) { + if (UTILS_UNLIKELY(ASurfaceTexture_attachToGLContext(aSurfaceTexture, uint32_t(tname)))) { // Unfortunately, before API 26 SurfaceTexture was always created in attached mode, // so attachToGLContext can fail. We consider this the unlikely case, because // this is how it should work. // So now we have to detach the surfacetexture from its texture ASurfaceTexture_detachFromGLContext(aSurfaceTexture); // and finally, try attaching again - ASurfaceTexture_attachToGLContext(aSurfaceTexture, (uint32_t)tname); + ASurfaceTexture_attachToGLContext(aSurfaceTexture, uint32_t(tname)); } } else { JNIEnv* const env = getEnvironment(); @@ -121,19 +122,19 @@ void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexce // associate our GL texture to the SurfaceTexture jobject jSurfaceTexture = stream->jSurfaceTexture; - env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, (jint)tname); + env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, jint(tname)); if (UTILS_UNLIKELY(env->ExceptionCheck())) { // Unfortunately, before API 26 SurfaceTexture was always created in attached mode, // so attachToGLContext can fail. We consider this the unlikely case, because // this is how it should work. env->ExceptionClear(); - // so now we have to detach the surfacetexture from its texture + // so now we have to detach the SurfaceTexture from its texture env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_detachFromGLContext); VirtualMachineEnv::handleException(env); // and finally, try attaching again - env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, (jint)tname); + env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, jint(tname)); VirtualMachineEnv::handleException(env); } } @@ -144,7 +145,7 @@ void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept { if (__builtin_available(android 28, *)) { ASurfaceTexture_detachFromGLContext(stream->nSurfaceTexture); } else { - JNIEnv* const env = mVm.getEnvironment(); + JNIEnv* const env = getEnvironment(); assert_invariant(env); // we should have called attach() by now env->CallVoidMethod(stream->jSurfaceTexture, mSurfaceTextureClass_detachFromGLContext); VirtualMachineEnv::handleException(env); @@ -152,12 +153,12 @@ void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept { } void ExternalStreamManagerAndroid::updateTexImage(Stream* handle, int64_t* timestamp) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { ASurfaceTexture_updateTexImage(stream->nSurfaceTexture); *timestamp = ASurfaceTexture_getTimestamp(stream->nSurfaceTexture); } else { - JNIEnv* const env = mVm.getEnvironment(); + JNIEnv* const env = getEnvironment(); assert_invariant(env); // we should have called attach() by now env->CallVoidMethod(stream->jSurfaceTexture, mSurfaceTextureClass_updateTexImage); VirtualMachineEnv::handleException(env); diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h index 9296a0e1c85e..d1257269c36b 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h @@ -21,14 +21,19 @@ #include +#include + #if __has_include() # include -# include #else struct ASurfaceTexture; typedef struct ASurfaceTexture ASurfaceTexture; #endif +#include + +#include + namespace filament::backend { /* @@ -70,7 +75,8 @@ class ExternalStreamManagerAndroid { ASurfaceTexture* nSurfaceTexture = nullptr; }; - inline JNIEnv* getEnvironment() noexcept { + // Must only be called from the backend thread + JNIEnv* getEnvironment() noexcept { JNIEnv* env = mJniEnv; if (UTILS_UNLIKELY(!env)) { return getEnvironmentSlow(); @@ -85,7 +91,6 @@ class ExternalStreamManagerAndroid { jmethodID mSurfaceTextureClass_attachToGLContext{}; jmethodID mSurfaceTextureClass_detachFromGLContext{}; }; - } // namespace filament::backend #endif //TNT_FILAMENT_BACKEND_OPENGL_ANDROID_EXTERNAL_STREAM_MANAGER_ANDROID_H diff --git a/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm b/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm index b62783c1dc0f..246f4c08ac01 100644 --- a/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm +++ b/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm @@ -54,8 +54,15 @@ CVOpenGLTextureCacheRef mTextureCache = nullptr; std::unique_ptr mExternalImageSharedGl; void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView); + struct ExternalImageCocoaGL : public Platform::ExternalImage { + CVPixelBufferRef cvBuffer; + protected: + ~ExternalImageCocoaGL() noexcept final; + }; }; +PlatformCocoaGLImpl::ExternalImageCocoaGL::~ExternalImageCocoaGL() noexcept = default; + CocoaGLSwapChain::CocoaGLSwapChain( NSView* inView ) : view(inView) , previousBounds(NSZeroRect) @@ -309,17 +316,12 @@ if (!pImpl->mExternalImageSharedGl) { pImpl->mExternalImageSharedGl = std::make_unique(); } - ExternalTexture* outTexture = new CocoaExternalImage(pImpl->mTextureCache, *pImpl->mExternalImageSharedGl); - - // the actual id/target will be set in setExternalImage. - outTexture->id = 0; - outTexture->target = GL_TEXTURE_2D; return outTexture; } -void PlatformCocoaGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformCocoaGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { auto* p = static_cast(texture); delete p; } @@ -344,6 +346,36 @@ return true; } +Platform::ExternalImageHandle PlatformCocoaGL::createExternalImage(void* cvPixelBuffer) noexcept { + auto* p = new(std::nothrow) PlatformCocoaGLImpl::ExternalImageCocoaGL; + p->cvBuffer = (CVPixelBufferRef) cvPixelBuffer; + return ExternalImageHandle{ p }; +} + +void PlatformCocoaGL::retainExternalImage(ExternalImageHandleRef externalImage) noexcept { + auto const* const cocoaGlExternalImage + = static_cast(externalImage.get()); + // Take ownership of the passed in buffer. It will be released the next time + // setExternalImage is called, or when the texture is destroyed. + CVPixelBufferRef pixelBuffer = cocoaGlExternalImage->cvBuffer; + CVPixelBufferRetain(pixelBuffer); +} + +bool PlatformCocoaGL::setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept { + auto const* const cocoaGlExternalImage + = static_cast(externalImage.get()); + CVPixelBufferRef cvPixelBuffer = cocoaGlExternalImage->cvBuffer; + CocoaExternalImage* cocoaExternalImage = static_cast(texture); + if (!cocoaExternalImage->set(cvPixelBuffer)) { + return false; + } + texture->target = cocoaExternalImage->getTarget(); + texture->id = cocoaExternalImage->getGlTexture(); + // we used to set the internalFormat, but it's not used anywhere on the gl backend side + // cocoaExternalImage->getInternalFormat(); + return true; +} + void PlatformCocoaGLImpl::updateOpenGLContext(NSView *nsView, bool resetView, bool clearView) { NSOpenGLContext* glContext = mGLContext; diff --git a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm index 326f55f06d2b..e37e61a1096c 100644 --- a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm +++ b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm @@ -47,8 +47,15 @@ GLuint mDefaultDepthbuffer = 0; CVOpenGLESTextureCacheRef mTextureCache = nullptr; CocoaTouchExternalImage::SharedGl* mExternalImageSharedGl = nullptr; + struct ExternalImageCocoaTouchGL : public Platform::ExternalImage { + CVPixelBufferRef cvBuffer; + protected: + ~ExternalImageCocoaTouchGL() noexcept final; + }; }; +PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL::~ExternalImageCocoaTouchGL() noexcept = default; + PlatformCocoaTouchGL::PlatformCocoaTouchGL() : pImpl(new PlatformCocoaTouchGLImpl) { } @@ -198,13 +205,10 @@ OpenGLPlatform::ExternalTexture* PlatformCocoaTouchGL::createExternalImageTexture() noexcept { ExternalTexture* outTexture = new CocoaTouchExternalImage(pImpl->mTextureCache, *pImpl->mExternalImageSharedGl); - // the actual id/target will be set in setExternalImage*( - outTexture->id = 0; - outTexture->target = GL_TEXTURE_2D; return outTexture; } -void PlatformCocoaTouchGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformCocoaTouchGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { auto* p = static_cast(texture); delete p; } @@ -229,4 +233,35 @@ return true; } +Platform::ExternalImageHandle PlatformCocoaTouchGL::createExternalImage(void* cvPixelBuffer) noexcept { + auto* p = new(std::nothrow) PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL; + p->cvBuffer = (CVPixelBufferRef) cvPixelBuffer; + return ExternalImageHandle{ p }; +} + +void PlatformCocoaTouchGL::retainExternalImage(ExternalImageHandleRef externalImage) noexcept { + auto const* const cocoaTouchGlExternalImage + = static_cast(externalImage.get()); + // Take ownership of the passed in buffer. It will be released the next time + // setExternalImage is called, or when the texture is destroyed. + CVPixelBufferRef pixelBuffer = cocoaTouchGlExternalImage->cvBuffer; + CVPixelBufferRetain(pixelBuffer); +} + +bool PlatformCocoaTouchGL::setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept { + auto const* const cocoaTouchGlExternalImage + = static_cast(externalImage.get()); + CVPixelBufferRef cvPixelBuffer = cocoaTouchGlExternalImage->cvBuffer; + CocoaTouchExternalImage* cocoaExternalImage = static_cast(texture); + if (!cocoaExternalImage->set(cvPixelBuffer)) { + return false; + } + texture->target = cocoaExternalImage->getTarget(); + texture->id = cocoaExternalImage->getGlTexture(); + // we used to set the internalFormat, but it's not used anywhere on the gl backend side + // cocoaExternalImage->getInternalFormat(); + return true; +} + + } // namespace filament::backend diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 9e6b628f02b9..3e141c463915 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -117,7 +117,9 @@ bool PlatformEGL::isOpenGL() const noexcept { return false; } -Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept { +PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default; + +Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept { mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert_invariant(mEGLDisplay != EGL_NO_DISPLAY); @@ -295,7 +297,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon clearGlError(); // success!! - return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig); + return createDefaultDriver(this, sharedContext, driverConfig); error: // if we're here, we've failed @@ -549,7 +551,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain( return sc; } -void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept { +void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); if (sc->sur != EGL_NO_SURFACE) { @@ -562,7 +564,7 @@ void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept { } } -bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept { +bool PlatformEGL::isSwapChainProtected(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT); @@ -583,10 +585,10 @@ bool PlatformEGL::makeCurrent(ContextType type, return success == EGL_TRUE ? true : false; } -void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain, - Platform::SwapChain* readSwapChain, - utils::Invocable preContextChange, - utils::Invocable postContextChange) noexcept { +void PlatformEGL::makeCurrent(SwapChain* drawSwapChain, + SwapChain* readSwapChain, + Invocable preContextChange, + Invocable postContextChange) noexcept { assert_invariant(drawSwapChain); assert_invariant(readSwapChain); @@ -645,7 +647,7 @@ void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain, } } -void PlatformEGL::commit(Platform::SwapChain* swapChain) noexcept { +void PlatformEGL::commit(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); if (sc->sur != EGL_NO_SURFACE) { @@ -668,7 +670,7 @@ Platform::Fence* PlatformEGL::createFence() noexcept { return f; } -void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept { +void PlatformEGL::destroyFence(Fence* fence) noexcept { #ifdef EGL_KHR_reusable_sync EGLSyncKHR sync = (EGLSyncKHR) fence; if (sync != EGL_NO_SYNC_KHR) { @@ -678,7 +680,7 @@ void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept { } FenceStatus PlatformEGL::waitFence( - Platform::Fence* fence, uint64_t timeout) noexcept { + Fence* fence, uint64_t timeout) noexcept { #ifdef EGL_KHR_reusable_sync EGLSyncKHR sync = (EGLSyncKHR) fence; if (sync != EGL_NO_SYNC_KHR) { @@ -699,16 +701,10 @@ FenceStatus PlatformEGL::waitFence( OpenGLPlatform::ExternalTexture* PlatformEGL::createExternalImageTexture() noexcept { ExternalTexture* outTexture = new(std::nothrow) ExternalTexture{}; glGenTextures(1, &outTexture->id); - if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - outTexture->target = GL_TEXTURE_EXTERNAL_OES; - } else { - // if texture external is not supported, revert to texture 2d - outTexture->target = GL_TEXTURE_2D; - } return outTexture; } -void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformEGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { glDeleteTextures(1, &texture->id); delete texture; } @@ -728,6 +724,18 @@ bool PlatformEGL::setExternalImage(void* externalImage, return true; } +Platform::ExternalImageHandle PlatformEGL::createExternalImage(EGLImageKHR eglImage) noexcept { + auto* const p = new(std::nothrow) ExternalImageEGL; + p->eglImage = eglImage; + return ExternalImageHandle{p}; +} + +bool PlatformEGL::setExternalImage(ExternalImageHandleRef externalImage, + UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { + auto const* const eglExternalImage = static_cast(externalImage.get()); + return setExternalImage(eglExternalImage->eglImage, texture); +} + // ----------------------------------------------------------------------------------------------- void PlatformEGL::initializeGlExtensions() noexcept { @@ -738,7 +746,7 @@ void PlatformEGL::initializeGlExtensions() noexcept { ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3"); } -EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept { +EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept { switch (type) { case ContextType::NONE: return EGL_NO_CONTEXT; diff --git a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp index 07e4b10d36d7..73828f74ca6e 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp @@ -231,6 +231,26 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext, return driver; } +PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default; + +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 }; +} + +bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage, + UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { + auto const* const eglExternalImage = static_cast(externalImage.get()); + if (eglExternalImage->aHardwareBuffer) { + // TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer + return true; + } + // not a AHardwareBuffer, fallback to the inherited version + return PlatformEGL::setExternalImage(externalImage, texture); +} + void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept { EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW); if (currentDrawSurface != EGL_NO_SURFACE) { diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp index bcb786e63aed..c88bc27f460b 100644 --- a/filament/backend/src/vulkan/VulkanBlitter.cpp +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -21,6 +21,7 @@ #include "VulkanHandles.h" #include "VulkanSamplerCache.h" #include "VulkanTexture.h" +#include "vulkan/utils/Image.h" #include #include @@ -61,8 +62,8 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V .dstOffsets = { dstRect[0], dstRect[1] }, }}; vkCmdBlitImage(cmdbuf, - src.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - dst.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), + src.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + dst.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, blitRegions, filter); if (oldSrcLayout == VulkanLayout::UNDEFINED) { @@ -104,8 +105,8 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect .extent = { src.getExtent2D().width, src.getExtent2D().height, 1 }, }}; vkCmdResolveImage(cmdbuffer, - src.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - dst.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), + src.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + dst.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, resolveRegions); if (oldSrcLayout == VulkanLayout::UNDEFINED) { diff --git a/filament/backend/src/vulkan/VulkanCommands.h b/filament/backend/src/vulkan/VulkanCommands.h index 2e331dfa4ada..0afd4b4b469b 100644 --- a/filament/backend/src/vulkan/VulkanCommands.h +++ b/filament/backend/src/vulkan/VulkanCommands.h @@ -23,8 +23,8 @@ #include "VulkanAsyncHandles.h" #include "VulkanConstants.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/StaticVector.h" #include #include @@ -79,7 +79,7 @@ struct VulkanCommandBuffer { void reset() noexcept; inline void insertWait(VkSemaphore sem) { - mWaitSemaphores.insert(sem); + mWaitSemaphores.push_back(sem); } void pushMarker(char const* marker) noexcept; @@ -115,7 +115,7 @@ struct VulkanCommandBuffer { bool const isProtected; VkDevice mDevice; VkQueue mQueue; - CappedArray mWaitSemaphores; + fvkutils::StaticVector mWaitSemaphores; VkCommandBuffer mBuffer; VkSemaphore mSubmission; VkFence mFence; diff --git a/filament/backend/src/vulkan/VulkanContext.cpp b/filament/backend/src/vulkan/VulkanContext.cpp index 95d860d618d0..0345e69cf983 100644 --- a/filament/backend/src/vulkan/VulkanContext.cpp +++ b/filament/backend/src/vulkan/VulkanContext.cpp @@ -20,7 +20,6 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 67c4e52a9b7b..aebc35505001 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -18,8 +18,8 @@ #define TNT_FILAMENT_BACKEND_VULKANCONTEXT_H #include "VulkanConstants.h" -#include "VulkanImageUtility.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Image.h" +#include "vulkan/utils/Definitions.h" #include "vulkan/memory/ResourcePointer.h" @@ -28,6 +28,8 @@ #include #include +#include + #include VK_DEFINE_HANDLE(VmaAllocator) @@ -113,11 +115,11 @@ struct VulkanContext { return (uint32_t) VK_MAX_MEMORY_TYPES; } - inline VkFormatList const& getAttachmentDepthStencilFormats() const { + inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const { return mDepthStencilFormats; } - inline VkFormatList const& getBlittableDepthStencilFormats() const { + inline fvkutils::VkFormatList const& getBlittableDepthStencilFormats() const { return mBlittableDepthStencilFormats; } @@ -175,8 +177,8 @@ struct VulkanContext { bool mLazilyAllocatedMemorySupported = false; bool mProtectedMemorySupported = false; - VkFormatList mDepthStencilFormats; - VkFormatList mBlittableDepthStencilFormats; + fvkutils::VkFormatList mDepthStencilFormats; + fvkutils::VkFormatList mBlittableDepthStencilFormats; // For convenience so that VulkanPlatform can initialize the private fields. friend class VulkanPlatform; diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 56c4a7a2964c..615cf0522112 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -26,9 +26,12 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "memory/ResourceManager.h" -#include "memory/ResourcePointer.h" +#include "vulkan/memory/ResourceManager.h" +#include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Definitions.h" +#include #include #include @@ -43,11 +46,13 @@ 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. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-stack-address" #pragma clang diagnostic ignored "-Wunused-parameter" +#endif namespace filament::backend { @@ -295,6 +300,10 @@ ShaderModel VulkanDriver::getShaderModel() const noexcept { #endif } +ShaderLanguage VulkanDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::SPIRV; +} + void VulkanDriver::terminate() { // Flush and wait here to make sure all queued commands are executed and resources that are tied // to those commands are no longer referenced. @@ -536,16 +545,25 @@ void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle::cast(&mResourceManager, srch); auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle); texture.inc(); } -void VulkanDriver::createTextureExternalImageR(Handle th, +void VulkanDriver::createTextureExternalImage2R(Handle th, backend::SamplerType target, backend::TextureFormat format, - uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) { + uint32_t width, uint32_t height, backend::TextureUsage usage, + Platform::ExternalImageHandleRef externalImage) { + FVK_SYSTRACE_SCOPE(); + + // FIXME: implement createTextureExternalImage2R +} + +void VulkanDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, + backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, + void* externalImage) { FVK_SYSTRACE_SCOPE(); const auto& metadata = mPlatform->getExternalImageMetadata(externalImage); @@ -555,7 +573,7 @@ void VulkanDriver::createTextureExternalImageR(Handle th, assert_invariant(width == metadata.width); assert_invariant(height == metadata.height); - assert_invariant(getVkFormat(format) == metadata.format); + assert_invariant(fvkutils::getVkFormat(format) == metadata.format); const auto& data = mPlatform->createExternalImage(externalImage, metadata); @@ -783,6 +801,10 @@ Handle VulkanDriver::createTextureViewSwizzleS() noexcept { return mResourceManager.allocHandle(); } +Handle VulkanDriver::createTextureExternalImage2S() noexcept { + return mResourceManager.allocHandle(); +} + Handle VulkanDriver::createTextureExternalImageS() noexcept { return mResourceManager.allocHandle(); } @@ -930,7 +952,7 @@ FenceStatus VulkanDriver::getFenceStatus(Handle fh) { // We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that // the GPU supports the given texture format with non-zero optimal tiling features. bool VulkanDriver::isTextureFormatSupported(TextureFormat format) { - VkFormat vkformat = getVkFormat(format); + VkFormat vkformat = fvkutils::getVkFormat(format); if (vkformat == VK_FORMAT_UNDEFINED) { return false; } @@ -957,7 +979,7 @@ bool VulkanDriver::isTextureFormatMipmappable(TextureFormat format) { } bool VulkanDriver::isRenderTargetFormatSupported(TextureFormat format) { - VkFormat vkformat = getVkFormat(format); + VkFormat vkformat = fvkutils::getVkFormat(format); if (vkformat == VK_FORMAT_UNDEFINED) { return false; } @@ -1015,12 +1037,11 @@ bool VulkanDriver::isDepthStencilResolveSupported() { bool VulkanDriver::isDepthStencilBlitSupported(TextureFormat format) { auto const& formats = mContext.getBlittableDepthStencilFormats(); - return std::find(formats.begin(), formats.end(), getVkFormat(format)) != formats.end(); + return std::find(formats.begin(), formats.end(), fvkutils::getVkFormat(format)) != + formats.end(); } -bool VulkanDriver::isProtectedTexturesSupported() { - return false; -} +bool VulkanDriver::isProtectedTexturesSupported() { return false; } bool VulkanDriver::isDepthClampSupported() { return mContext.isDepthClampSupported(); @@ -1091,8 +1112,8 @@ FeatureLevel VulkanDriver::getFeatureLevel() { math::float2 VulkanDriver::getClipSpaceParams() { // virtual and physical z-coordinate of clip-space is in [-w, 0] - // Note: this is actually never used (see: main.vs), but it's a backend API, so we implement it - // properly. + // Note: this is actually never used (see: surface_main.vs), but it's a backend API, so we + // implement it properly. return math::float2{ 1.0f, 0.0f }; } @@ -1163,6 +1184,9 @@ void VulkanDriver::update3DImage(Handle th, uint32_t level, uint32_t scheduleDestroy(std::move(data)); } +void VulkanDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { +} + void VulkanDriver::setupExternalImage(void* image) { } @@ -1673,25 +1697,25 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { auto rt = mCurrentRenderPass.renderTarget; VulkanPipelineCache::RasterState const vulkanRasterState{ - .cullMode = getCullMode(rasterState.culling), - .frontFace = getFrontFace(rasterState.inverseFrontFaces), + .cullMode = fvkutils::getCullMode(rasterState.culling), + .frontFace = fvkutils::getFrontFace(rasterState.inverseFrontFaces), .depthBiasEnable = (depthOffset.constant || depthOffset.slope) ? true : false, .blendEnable = rasterState.hasBlending(), .depthWriteEnable = rasterState.depthWrite, .alphaToCoverageEnable = rasterState.alphaToCoverage, - .srcColorBlendFactor = getBlendFactor(rasterState.blendFunctionSrcRGB), - .dstColorBlendFactor = getBlendFactor(rasterState.blendFunctionDstRGB), - .srcAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionSrcAlpha), - .dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha), + .srcColorBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionSrcRGB), + .dstColorBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionDstRGB), + .srcAlphaBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionSrcAlpha), + .dstAlphaBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionDstAlpha), .colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0), .rasterizationSamples = rt->getSamples(), .depthClamp = rasterState.depthClamp, .colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass), .colorBlendOp = rasterState.blendEquationRGB, - .alphaBlendOp = rasterState.blendEquationAlpha, + .alphaBlendOp = rasterState.blendEquationAlpha, .depthCompareOp = rasterState.depthFunc, .depthBiasConstantFactor = depthOffset.constant, - .depthBiasSlopeFactor = depthOffset.slope + .depthBiasSlopeFactor = depthOffset.slope, }; // unfortunately in Vulkan the topology is per pipeline @@ -1728,7 +1752,7 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { mBoundPipeline = { .program = program, .pipelineLayout = pipelineLayout, - .descriptorSetMask = DescriptorSetMask(descriptorSetMaskTable[layoutCount]), + .descriptorSetMask = fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]), }; mPipelineCache.bindLayout(pipelineLayout); @@ -1877,4 +1901,6 @@ template class ConcreteDispatcher; } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index 83215a2ce502..1621dc110636 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -26,12 +26,13 @@ #include "VulkanReadPixels.h" #include "VulkanSamplerCache.h" #include "VulkanStagePool.h" -#include "VulkanUtility.h" +#include "vulkan/caching/VulkanDescriptorSetManager.h" +#include "vulkan/caching/VulkanPipelineLayoutCache.h" +#include "vulkan/memory/ResourceManager.h" +#include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Definitions.h" + #include "backend/DriverEnums.h" -#include "caching/VulkanDescriptorSetManager.h" -#include "caching/VulkanPipelineLayoutCache.h" -#include "memory/ResourceManager.h" -#include "memory/ResourcePointer.h" #include "DriverBase.h" #include "private/backend/Driver.h" @@ -93,6 +94,7 @@ class VulkanDriver final : public DriverBase { Dispatcher getDispatcher() const noexcept final; ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; template friend class ConcreteDispatcher; @@ -141,13 +143,14 @@ class VulkanDriver final : public DriverBase { struct { resource_ptr program; VkPipelineLayout pipelineLayout; - DescriptorSetMask descriptorSetMask; + fvkutils::DescriptorSetMask descriptorSetMask; } mBoundPipeline = {}; // We need to store information about a render pass to enable better barriers at the end of a // renderpass. struct { - using AttachmentArray = CappedArray; + using AttachmentArray = + fvkutils::StaticVector; AttachmentArray attachments; } mRenderPassFboInfo = {}; diff --git a/filament/backend/src/vulkan/VulkanFboCache.cpp b/filament/backend/src/vulkan/VulkanFboCache.cpp index 3d76424e3683..936b6672c2d3 100644 --- a/filament/backend/src/vulkan/VulkanFboCache.cpp +++ b/filament/backend/src/vulkan/VulkanFboCache.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "vulkan/VulkanFboCache.h" - -#include +#include "VulkanFboCache.h" #include "VulkanConstants.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Image.h" + +#include // If any VkRenderPass or VkFramebuffer is unused for more than TIME_BEFORE_EVICTION frames, it // is evicted from the cache. @@ -214,7 +214,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) { continue; } - const VkImageLayout subpassLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT); + const VkImageLayout subpassLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT); uint32_t index; if (!hasSubpasses) { @@ -259,8 +259,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = (config.usesLazilyAllocatedMemory & (1 << i)) ? kDisableStore : kEnableStore, .stencilLoadOp = kDontCare, .stencilStoreOp = kDisableStore, - .initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), - .finalLayout = imgutil::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), + .finalLayout = fvkutils::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), }; } @@ -287,7 +287,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept pResolveAttachment->attachment = attachmentIndex; pResolveAttachment->layout - = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT_RESOLVE); + = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT_RESOLVE); ++pResolveAttachment; attachments[attachmentIndex++] = { @@ -297,8 +297,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = kEnableStore, .stencilLoadOp = kDontCare, .stencilStoreOp = kDisableStore, - .initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), - .finalLayout = imgutil::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), + .finalLayout = fvkutils::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), }; } @@ -307,7 +307,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept const bool clear = any(config.clear & TargetBufferFlags::DEPTH); const bool discardStart = any(config.discardStart & TargetBufferFlags::DEPTH); const bool discardEnd = any(config.discardEnd & TargetBufferFlags::DEPTH); - depthAttachmentRef.layout = imgutil::getVkLayout(VulkanLayout::DEPTH_ATTACHMENT); + depthAttachmentRef.layout = fvkutils::getVkLayout(VulkanLayout::DEPTH_ATTACHMENT); depthAttachmentRef.attachment = attachmentIndex; attachments[attachmentIndex++] = { .format = config.depthFormat, @@ -316,8 +316,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = discardEnd ? kDisableStore : kEnableStore, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = imgutil::getVkLayout(config.initialDepthLayout), - .finalLayout = imgutil::getVkLayout(FINAL_DEPTH_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(config.initialDepthLayout), + .finalLayout = fvkutils::getVkLayout(FINAL_DEPTH_ATTACHMENT_LAYOUT), }; } renderPassInfo.attachmentCount = attachmentIndex; diff --git a/filament/backend/src/vulkan/VulkanHandles.cpp b/filament/backend/src/vulkan/VulkanHandles.cpp index 29c33a82b193..3a7ac6b134ef 100644 --- a/filament/backend/src/vulkan/VulkanHandles.cpp +++ b/filament/backend/src/vulkan/VulkanHandles.cpp @@ -22,9 +22,11 @@ #include "VulkanDriver.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" -#include "spirv/VulkanSpirvUtils.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Definitions.h" +#include "vulkan/utils/Image.h" +#include "vulkan/utils/Spirv.h" #include @@ -56,10 +58,10 @@ template inline void fromStageFlags(backend::ShaderStageFlags stage, descriptor_binding_t binding, Bitmask& mask) { if ((bool) (stage & ShaderStageFlags::VERTEX)) { - mask.set(binding + getVertexStageShift()); + mask.set(binding + fvkutils::getVertexStageShift()); } if ((bool) (stage & ShaderStageFlags::FRAGMENT)) { - mask.set(binding + getFragmentStageShift()); + mask.set(binding + fvkutils::getFragmentStageShift()); } } @@ -206,7 +208,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept size_t dataSize = blob.size(); if (!specializationConstants.empty()) { - workaroundSpecConstant(blob, specializationConstants, shader); + fvkutils::workaroundSpecConstant(blob, specializationConstants, shader); data = (uint32_t*) shader.data(); dataSize = shader.size() * 4; } @@ -314,8 +316,8 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica // Constrain the sample count according to both kinds of sample count masks obtained from // VkPhysicalDeviceProperties. This is consistent with the VulkanTexture constructor. auto const& limits = context.getPhysicalDeviceLimits(); - samples = reduceSampleCount(samples, limits.framebufferDepthSampleCounts & - limits.framebufferColorSampleCounts); + samples = samples = fvkutils::reduceSampleCount(samples, + limits.framebufferDepthSampleCounts & limits.framebufferColorSampleCounts); auto& rpkey = mInfo->rpkey; rpkey.samples = samples; @@ -498,7 +500,7 @@ VulkanVertexBufferInfo::VulkanVertexBufferInfo( Attribute attrib = attributes[attribIndex]; bool const isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET; bool const isNormalized = attrib.flags & Attribute::FLAG_NORMALIZED; - VkFormat vkformat = getVkFormat(attrib.type, isNormalized, isInteger); + VkFormat vkformat = fvkutils::getVkFormat(attrib.type, isNormalized, isInteger); // HACK: Re-use the positions buffer as a dummy buffer for disabled attributes. Filament's // vertex shaders declare all attributes as either vec4 or uvec4 (the latter for bone diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h index 325098522835..f3656ee6de0e 100644 --- a/filament/backend/src/vulkan/VulkanHandles.h +++ b/filament/backend/src/vulkan/VulkanHandles.h @@ -25,8 +25,9 @@ #include "VulkanFboCache.h" #include "VulkanSwapChain.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include "vulkan/memory/Resource.h" +#include "vulkan/utils/StaticVector.h" +#include "vulkan/utils/Definitions.h" #include @@ -44,11 +45,11 @@ namespace { template inline uint8_t collapsedCount(Bitmask const& mask) { static_assert(sizeof(mask) <= 64); - constexpr uint64_t VERTEX_MASK = (1ULL << getFragmentStageShift()) - 1ULL; - constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << getFragmentStageShift()); + constexpr uint64_t VERTEX_MASK = (1ULL << fvkutils::getFragmentStageShift()) - 1ULL; + constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << fvkutils::getFragmentStageShift()); uint64_t val = mask.getValue(); - val = ((val & VERTEX_MASK) >> getVertexStageShift()) | - ((val & FRAGMENT_MASK) >> getFragmentStageShift()); + val = ((val & VERTEX_MASK) >> fvkutils::getVertexStageShift()) | + ((val & FRAGMENT_MASK) >> fvkutils::getFragmentStageShift()); return (uint8_t) Bitmask(val).count(); } @@ -67,10 +68,10 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso // The bitmask representation of a set layout. struct Bitmask { // TODO: better utiltize the space below and use bitset instead. - UniformBufferBitmask ubo; // 8 bytes - UniformBufferBitmask dynamicUbo; // 8 bytes - SamplerBitmask sampler; // 8 bytes - InputAttachmentBitmask inputAttachment; // 8 bytes + fvkutils::UniformBufferBitmask ubo; // 8 bytes + fvkutils::UniformBufferBitmask dynamicUbo; // 8 bytes + fvkutils::SamplerBitmask sampler; // 8 bytes + fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes bool operator==(Bitmask const& right) const { return ubo == right.ubo && dynamicUbo == right.dynamicUbo && sampler == right.sampler && @@ -138,7 +139,7 @@ struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource { using OnRecycle = std::function; VulkanDescriptorSet(VkDescriptorSet rawSet, - UniformBufferBitmask const& dynamicUboMask, + fvkutils::UniformBufferBitmask const& dynamicUboMask, uint8_t uniqueDynamicUboCount, OnRecycle&& onRecycleFn) : vkSet(rawSet), @@ -164,7 +165,7 @@ struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource { void acquire(fvkmemory::resource_ptr buffer); VkDescriptorSet const vkSet; - UniformBufferBitmask const dynamicUboMask; + fvkutils::UniformBufferBitmask const dynamicUboMask; uint8_t const uniqueDynamicUboCount; private: @@ -193,7 +194,7 @@ struct PushConstantDescription { }; struct VulkanProgram : public HwProgram, fvkmemory::Resource { - using BindingList = CappedArray; + using BindingList = fvkutils::StaticVector; VulkanProgram(VkDevice device, Program const& builder) noexcept; ~VulkanProgram(); diff --git a/filament/backend/src/vulkan/VulkanMemory.cpp b/filament/backend/src/vulkan/VulkanMemory.cpp index 16f94346a7cb..4e6de735a351 100644 --- a/filament/backend/src/vulkan/VulkanMemory.cpp +++ b/filament/backend/src/vulkan/VulkanMemory.cpp @@ -16,6 +16,7 @@ #include // must be included before vk_mem_alloc +#if defined(__clang__) #pragma clang diagnostic push // Needed because not all clang versions have the warning -Wdeprecated-copy. @@ -32,6 +33,7 @@ #pragma clang diagnostic ignored "-Wextra-semi" #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" #pragma clang diagnostic ignored "-Wthread-safety-analysis" +#endif static const PFN_vkGetInstanceProcAddr& vkGetInstanceProcAddr = bluevk::vkGetInstanceProcAddr; static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceProcAddr; @@ -39,4 +41,7 @@ static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceP #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_IMPLEMENTATION #include "vk_mem_alloc.h" + +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanMemory.h b/filament/backend/src/vulkan/VulkanMemory.h index a5ab29531921..d16cd515a87d 100644 --- a/filament/backend/src/vulkan/VulkanMemory.h +++ b/filament/backend/src/vulkan/VulkanMemory.h @@ -27,7 +27,9 @@ #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #endif +#if defined(__clang__) #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" +#endif #include "vk_mem_alloc.h" diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 4cf98cef15a7..e7fc0431c776 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -24,12 +24,14 @@ #include "VulkanConstants.h" #include "VulkanHandles.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" +#if defined(__clang__) // Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer // to a stack-allocated variable. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-stack-address" +#endif using namespace bluevk; @@ -194,7 +196,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n vkDs.depthTestEnable = VK_TRUE; vkDs.depthWriteEnable = raster.depthWriteEnable; - vkDs.depthCompareOp = getCompareOp(raster.depthCompareOp); + vkDs.depthCompareOp = fvkutils::getCompareOp(raster.depthCompareOp); vkDs.depthBoundsTestEnable = VK_FALSE; vkDs.stencilTestEnable = VK_FALSE; vkDs.minDepthBounds = 0.0f; @@ -323,4 +325,6 @@ bool VulkanPipelineCache::PipelineEqual::operator()(const PipelineKey& k1, } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index c0500fbb8be9..a3f372fb259b 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -19,7 +19,6 @@ #include "VulkanCommands.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" #include #include @@ -68,8 +67,10 @@ class VulkanPipelineCache { VkSpecializationInfo* specializationInfos = nullptr; }; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic warning "-Wpadded" +#endif // The RasterState POD contains standard graphics-related state like blending, culling, etc. // The following states are omitted because Filament never changes them: @@ -212,7 +213,9 @@ class VulkanPipelineCache { bool operator()(const PipelineKey& k1, const PipelineKey& k2) const; }; +#if defined(__clang__) #pragma clang diagnostic pop +#endif // CACHE ENTRY STRUCTS // ------------------- diff --git a/filament/backend/src/vulkan/VulkanReadPixels.cpp b/filament/backend/src/vulkan/VulkanReadPixels.cpp index 48df6c722276..7e7008ab149d 100644 --- a/filament/backend/src/vulkan/VulkanReadPixels.cpp +++ b/filament/backend/src/vulkan/VulkanReadPixels.cpp @@ -19,8 +19,9 @@ #include "DataReshaper.h" #include "VulkanCommands.h" #include "VulkanHandles.h" -#include "VulkanImageUtility.h" #include "VulkanTexture.h" +#include "vulkan/utils/Conversion.h" // getComponentType() +#include "vulkan/utils/Image.h" #include @@ -218,7 +219,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget }; vkBeginCommandBuffer(cmdbuffer, &binfo); - imgutil::transitionLayout(cmdbuffer, { + fvkutils::transitionLayout(cmdbuffer, { .image = stagingImage, .oldLayout = VulkanLayout::UNDEFINED, .newLayout = VulkanLayout::TRANSFER_DST, @@ -265,8 +266,8 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget imageCopyRegion.srcOffset.y + imageCopyRegion.extent.height <= srcExtent.height); vkCmdCopyImage(cmdbuffer, srcAttachment.getImage(), - imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), stagingImage, - imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion); + fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), stagingImage, + fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion); // Restore the source image layout. srcTexture->transitionLayout(cmdbuffer, srcRange, srcTexture->getDefaultLayout()); @@ -318,8 +319,8 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget vkMapMemory(device, stagingMemory, 0, VK_WHOLE_SIZE, 0, (void**) &srcPixels); srcPixels += subResourceLayout.offset; - if (!DataReshaper::reshapeImage(&p, getComponentType(srcFormat), - getComponentCount(srcFormat), srcPixels, + if (!DataReshaper::reshapeImage(&p, fvkutils::getComponentType(srcFormat), + fvkutils::getComponentCount(srcFormat), srcPixels, static_cast(subResourceLayout.rowPitch), static_cast(width), static_cast(height), swizzle)) { FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl; diff --git a/filament/backend/src/vulkan/VulkanSamplerCache.cpp b/filament/backend/src/vulkan/VulkanSamplerCache.cpp index 75a2578e75e4..005c16c52571 100644 --- a/filament/backend/src/vulkan/VulkanSamplerCache.cpp +++ b/filament/backend/src/vulkan/VulkanSamplerCache.cpp @@ -15,6 +15,7 @@ */ #include "vulkan/VulkanSamplerCache.h" +#include "vulkan/utils/Conversion.h" #include @@ -114,7 +115,7 @@ VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept { .anisotropyEnable = params.anisotropyLog2 == 0 ? 0u : 1u, .maxAnisotropy = (float)(1u << params.anisotropyLog2), .compareEnable = getCompareEnable(params.compareMode), - .compareOp = getCompareOp(params.compareFunc), + .compareOp = fvkutils::getCompareOp(params.compareFunc), .minLod = 0.0f, .maxLod = getMaxLod(params.filterMin), .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, diff --git a/filament/backend/src/vulkan/VulkanSamplerCache.h b/filament/backend/src/vulkan/VulkanSamplerCache.h index cb5fe43ce4c5..31e902c5824d 100644 --- a/filament/backend/src/vulkan/VulkanSamplerCache.h +++ b/filament/backend/src/vulkan/VulkanSamplerCache.h @@ -18,7 +18,6 @@ #define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H #include "VulkanContext.h" -#include "VulkanUtility.h" #include diff --git a/filament/backend/src/vulkan/VulkanStagePool.cpp b/filament/backend/src/vulkan/VulkanStagePool.cpp index cae1e85d257f..02e0f0eab11f 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.cpp +++ b/filament/backend/src/vulkan/VulkanStagePool.cpp @@ -18,9 +18,9 @@ #include "VulkanCommands.h" #include "VulkanConstants.h" -#include "VulkanImageUtility.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Image.h" #include @@ -72,7 +72,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) { VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, PixelDataType type, uint32_t width, uint32_t height) { - const VkFormat vkformat = getVkFormat(format, type); + const VkFormat vkformat = fvkutils::getVkFormat(format, type); for (auto image : mFreeImages) { if (image->format == vkformat && image->width == width && image->height == height) { mFreeImages.erase(image); @@ -113,7 +113,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi assert_invariant(result == VK_SUCCESS); - VkImageAspectFlags const aspectFlags = getImageAspect(vkformat); + VkImageAspectFlags const aspectFlags = fvkutils::getImageAspect(vkformat); VkCommandBuffer const cmdbuffer = mCommands->get().buffer(); // We use VK_IMAGE_LAYOUT_GENERAL here because the spec says: @@ -122,7 +122,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi // VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL layout. Calling // vkGetImageSubresourceLayout for a linear image returns a subresource layout mapping that is // valid for either of those image layouts." - imgutil::transitionLayout(cmdbuffer, { + fvkutils::transitionLayout(cmdbuffer, { .image = image->image, .oldLayout = VulkanLayout::UNDEFINED, .newLayout = VulkanLayout::READ_WRITE, // (= VK_IMAGE_LAYOUT_GENERAL) diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp index 2f30ee20c9a6..ff3f4f9a2b87 100644 --- a/filament/backend/src/vulkan/VulkanTexture.cpp +++ b/filament/backend/src/vulkan/VulkanTexture.cpp @@ -17,8 +17,8 @@ #include "VulkanCommands.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Conversion.h" #include #include @@ -152,7 +152,7 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator, bool isProtected) : mVkFormat(format), mViewType(viewType), - mFullViewRange{filament::backend::getImageAspect(format), 0, levels, 0, layerCount}, + mFullViewRange{fvkutils::getImageAspect(format), 0, levels, 0, layerCount}, mDefaultLayout(defaultLayout), mIsProtected(isProtected), mStagePool(stagePool), @@ -169,7 +169,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator, : HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED, tusage), mState(fvkmemory::resource_ptr::construct(resourceManager, device, - allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D), + allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D), 1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) { mState->mTextureImage = image; mState->mTextureImageMemory = memory; @@ -183,9 +183,10 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool) : HwTexture(target, levels, samples, w, h, depth, tformat, tusage), + mState(fvkmemory::resource_ptr::construct(resourceManager, device, - allocator, commands, stagePool, backend::getVkFormat(tformat), - imgutil::getViewType(target), levels, getLayerCount(target, depth), + allocator, commands, stagePool, fvkutils::getVkFormat(tformat), + fvkutils::getViewType(target), levels, getLayerCount(target, depth), VulkanLayout::UNDEFINED, any(usage & TextureUsage::PROTECTED))) { // Create an appropriately-sized device-only VkImage, but do not fill it yet. VkImageCreateInfo imageInfo{ @@ -281,16 +282,17 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, // any kind of attachment (color or depth). const auto& limits = context.getPhysicalDeviceLimits(); if (imageInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) { - samples = reduceSampleCount(samples, isVkDepthFormat(mState->mVkFormat) - ? limits.sampledImageDepthSampleCounts - : limits.sampledImageColorSampleCounts); + samples = fvkutils::reduceSampleCount(samples, + fvkutils::isVkDepthFormat(mState->mVkFormat) + ? limits.sampledImageDepthSampleCounts + : limits.sampledImageColorSampleCounts); } if (imageInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { - samples = reduceSampleCount(samples, limits.framebufferColorSampleCounts); + samples = fvkutils::reduceSampleCount(samples, limits.framebufferColorSampleCounts); } if (imageInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - samples = reduceSampleCount(samples, limits.sampledImageDepthSampleCounts); + samples = fvkutils::reduceSampleCount(samples, limits.sampledImageDepthSampleCounts); } this->samples = samples; imageInfo.samples = (VkSampleCountFlagBits) samples; @@ -401,8 +403,8 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt } // If format conversion is both required and supported, use vkCmdBlitImage. - const VkFormat hostFormat = backend::getVkFormat(hostData->format, hostData->type); - const VkFormat deviceFormat = getVkFormatLinear(mState->mVkFormat); + const VkFormat hostFormat = fvkutils::getVkFormat(hostData->format, hostData->type); + const VkFormat deviceFormat = fvkutils::getVkFormatLinear(mState->mVkFormat); if (hostFormat != deviceFormat && hostFormat != VK_FORMAT_UNDEFINED) { assert_invariant(xoffset == 0 && yoffset == 0 && zoffset == 0 && "Offsets not yet supported when format conversion is required."); @@ -461,7 +463,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt VulkanLayout const newLayout = VulkanLayout::TRANSFER_DST; VulkanLayout nextLayout = getLayout(transitionRange.baseArrayLayer, miplevel); - VkImageLayout const newVkLayout = imgutil::getVkLayout(newLayout); + VkImageLayout const newVkLayout = fvkutils::getVkLayout(newLayout); if (nextLayout == VulkanLayout::UNDEFINED) { nextLayout = getDefaultLayout(); @@ -508,8 +510,8 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u VulkanLayout const oldLayout = getLayout(layer, miplevel); transitionLayout(&commands, range, newLayout); - vkCmdBlitImage(cmdbuf, stage->image, imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - mState->mTextureImage, imgutil::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); + vkCmdBlitImage(cmdbuf, stage->image, fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + mState->mTextureImage, fvkutils::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); transitionLayout(&commands, range, oldLayout); } @@ -557,7 +559,7 @@ VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range, VkImageVi VkImageAspectFlags VulkanTexture::getImageAspect() const { // Helper function in VulkanUtility - return filament::backend::getImageAspect(mState->mVkFormat); + return fvkutils::getImageAspect(mState->mVkFormat); } bool VulkanTexture::transitionLayout(VulkanCommandBuffer* commands, @@ -600,7 +602,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR if (layout == newLayout) { continue; } - hasTransitions = hasTransitions || imgutil::transitionLayout(cmdbuf, { + hasTransitions = hasTransitions || fvkutils::transitionLayout(cmdbuf, { .image = mState->mTextureImage, .oldLayout = layout, .newLayout = newLayout, @@ -615,7 +617,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR } } } else if (newLayout != oldLayout) { - hasTransitions = imgutil::transitionLayout(cmdbuf, { + hasTransitions = fvkutils::transitionLayout(cmdbuf, { .image = mState->mTextureImage, .oldLayout = oldLayout, .newLayout = newLayout, @@ -650,7 +652,7 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); VkImageLayout const layout = - imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); + fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, @@ -673,7 +675,7 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); VkImageLayout const layout - = imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); + = fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, diff --git a/filament/backend/src/vulkan/VulkanTexture.h b/filament/backend/src/vulkan/VulkanTexture.h index 1889adf1212a..7f1cfe4e42ee 100644 --- a/filament/backend/src/vulkan/VulkanTexture.h +++ b/filament/backend/src/vulkan/VulkanTexture.h @@ -20,9 +20,9 @@ #include "DriverBase.h" #include "VulkanBuffer.h" -#include "VulkanImageUtility.h" #include "vulkan/memory/Resource.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Image.h" #include #include diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp index 19aa989b8c01..570dcc5df21c 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp @@ -16,11 +16,10 @@ #include "VulkanDescriptorSetManager.h" -#include -#include -#include -#include -#include +#include "vulkan/VulkanCommands.h" +#include "vulkan/VulkanHandles.h" +#include "vulkan/VulkanConstants.h" + #include #include @@ -207,17 +206,17 @@ uint32_t createBindings(VkDescriptorSetLayoutBinding* toBind, uint32_t count, Vk mask.forEachSetBit([&](size_t index) { VkShaderStageFlags stages = 0; uint32_t binding = 0; - if (index < getFragmentStageShift()) { + if (index < fvkutils::getFragmentStageShift()) { binding = (uint32_t) index; stages |= VK_SHADER_STAGE_VERTEX_BIT; - auto fragIndex = index + getFragmentStageShift(); + 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 - getFragmentStageShift()); + binding = (uint32_t) (index - fvkutils::getFragmentStageShift()); stages |= VK_SHADER_STAGE_FRAGMENT_BIT; } @@ -346,7 +345,6 @@ class VulkanDescriptorSetManager::DescriptorSetLayoutManager { mVkLayouts; }; - VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager) : mDevice(device), @@ -376,10 +374,10 @@ void VulkanDescriptorSetManager::unbind(uint8_t setIndex) { } void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, - VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask) { + 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. - DescriptorSetMask curMask = setMask; + fvkutils::DescriptorSetMask curMask = setMask; auto& updateSets = mStashedSets; auto& lastBoundSets = mLastBoundInfo.boundSets; @@ -458,7 +456,7 @@ void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptrgetViewForType(range, expectedType); } - info.imageLayout = imgutil::getVkLayout(texture->getDefaultLayout()); + info.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()); VkWriteDescriptorSet const descriptorWrite = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h index faeeb1442058..87aa076213e6 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h @@ -18,9 +18,8 @@ #define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H #include "vulkan/VulkanHandles.h" -#include "vulkan/VulkanTexture.h" -#include "vulkan/VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Definitions.h" // For DescriptorSetMask #include #include @@ -68,7 +67,7 @@ class VulkanDescriptorSetManager { void unbind(uint8_t setIndex); void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, - DescriptorSetMask const& setMask); + fvkutils::DescriptorSetMask const& setMask); fvkmemory::resource_ptr createSet(Handle handle, fvkmemory::resource_ptr layout); @@ -93,7 +92,7 @@ class VulkanDescriptorSetManager { struct { VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - DescriptorSetMask setMask; + fvkutils::DescriptorSetMask setMask; DescriptorSetArray boundSets = {}; } mLastBoundInfo; }; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index e20ae0270cd6..c76a1a08dd0d 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -21,7 +21,7 @@ #include "vulkan/platform/VulkanPlatformSwapChainImpl.h" #include "vulkan/VulkanConstants.h" #include "vulkan/VulkanDriver.h" -#include "vulkan/VulkanUtility.h" +#include "vulkan/utils/Helper.h" #include #include @@ -126,7 +126,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) { const int minor = VK_VERSION_MINOR(deviceProperties.apiVersion); const FixedCapacityVector physicalDevices - = filament::backend::enumerate(vkEnumeratePhysicalDevices, instance); + = fvkutils::enumerate(vkEnumeratePhysicalDevices, instance); FVK_LOGI << "Selected physical device '" << deviceProperties.deviceName << "' from " << physicalDevices.size() << " physical devices. " @@ -172,7 +172,7 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts = }; ExtensionSet exts; FixedCapacityVector const availableExts = - filament::backend::enumerate(vkEnumerateInstanceExtensionProperties, + fvkutils::enumerate(vkEnumerateInstanceExtensionProperties, static_cast(nullptr) /* pLayerName */); for (auto const& extProps: availableExts) { utils::CString name { extProps.extensionName }; @@ -212,7 +212,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) { ExtensionSet exts; // Identify supported physical device extensions FixedCapacityVector const extensions - = filament::backend::enumerate(vkEnumerateDeviceExtensionProperties, device, + = fvkutils::enumerate(vkEnumerateDeviceExtensionProperties, device, static_cast(nullptr) /* pLayerName */); for (auto const& extension: extensions) { utils::CString name { extension.extensionName }; @@ -473,7 +473,7 @@ inline int deviceTypeOrder(VkPhysicalDeviceType deviceType) { VkPhysicalDevice selectPhysicalDevice(VkInstance instance, VulkanPlatform::Customization::GPUPreference const& gpuPreference) { FixedCapacityVector const physicalDevices = - filament::backend::enumerate(vkEnumeratePhysicalDevices, instance); + fvkutils::enumerate(vkEnumeratePhysicalDevices, instance); struct DeviceInfo { VkPhysicalDevice device = VK_NULL_HANDLE; VkPhysicalDeviceType deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER; @@ -508,7 +508,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance, // Does the device support the VK_KHR_swapchain extension? FixedCapacityVector const extensions - = filament::backend::enumerate(vkEnumerateDeviceExtensionProperties, + = fvkutils::enumerate(vkEnumerateDeviceExtensionProperties, candidateDevice, static_cast(nullptr) /* pLayerName */); bool supportsSwapchain = false; for (auto const& extension: extensions) { @@ -560,7 +560,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance, return device; } -VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { +fvkutils::VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { VkFormatFeatureFlags const features = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; // The ordering here indicates the preference of choosing depth+stencil format. @@ -579,17 +579,17 @@ VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { selectedFormats.push_back(format); } } - VkFormatList ret(selectedFormats.size()); + fvkutils::VkFormatList ret(selectedFormats.size()); std::copy(selectedFormats.begin(), selectedFormats.end(), ret.begin()); return ret; } -VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { +fvkutils::VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { std::vector selectedFormats; VkFormatFeatureFlags const required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; - for (VkFormat format : ALL_VK_FORMATS) { - if (isVkDepthFormat(format)) { + for (VkFormat format : fvkutils::ALL_VK_FORMATS) { + if (fvkutils::isVkDepthFormat(format)) { VkFormatProperties props; vkGetPhysicalDeviceFormatProperties(device, format, &props); if ((props.optimalTilingFeatures & required) == required) { @@ -597,7 +597,7 @@ VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { } } } - VkFormatList ret(selectedFormats.size()); + fvkutils::VkFormatList ret(selectedFormats.size()); std::copy(selectedFormats.begin(), selectedFormats.end(), ret.begin()); return ret; } diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp index 0ea9df5fa469..268f2a4d02d8 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp @@ -199,7 +199,6 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkGetAndroidHardwareBufferProperties failed with error=" << static_cast(result); - FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format) << "mismatched image format for external image (AHB)"; metadata.externalFormat = formatInfo.externalFormat; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp index cb80e4898501..921b8c56eb51 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp @@ -17,7 +17,9 @@ #include "VulkanPlatformSwapChainImpl.h" #include "vulkan/VulkanConstants.h" -#include "vulkan/VulkanUtility.h" +#include "vulkan/utils/Definitions.h" +#include "vulkan/utils/Helper.h" +#include "vulkan/utils/Image.h" #include @@ -29,9 +31,8 @@ namespace filament::backend { namespace { std::tuple createImageAndMemory(VulkanContext const& context, - VkDevice device, VkExtent2D extent, VkFormat format, - bool isProtected) { - bool const isDepth = isVkDepthFormat(format); + VkDevice device, VkExtent2D extent, VkFormat format, bool isProtected) { + bool const isDepth = fvkutils::isVkDepthFormat(format); // Filament expects blit() to work with any texture, so we almost always set these usage flags // (see copyFrame() and readPixels()). VkImageUsageFlags const blittable = @@ -83,9 +84,9 @@ std::tuple createImageAndMemory(VulkanContext const& co return std::tuple(image, imageMemory); } -VkFormat selectDepthFormat(VkFormatList const& depthFormats, bool hasStencil) { +VkFormat selectDepthFormat(fvkutils::VkFormatList const& depthFormats, bool hasStencil) { auto const formatItr = std::find_if(depthFormats.begin(), depthFormats.end(), - hasStencil ? isVkStencilFormat : isVkDepthFormat); + hasStencil ? fvkutils::isVkStencilFormat : fvkutils::isVkDepthFormat); assert_invariant( formatItr != depthFormats.end() && "Cannot find suitable swapchain depth format"); return *formatItr; @@ -169,7 +170,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { // Find a suitable surface format. FixedCapacityVector const surfaceFormats - = enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface); + = fvkutils::enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface); std::array expectedFormats = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, @@ -193,8 +194,8 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { // Verify that our chosen present mode is supported. In practice all devices support the FIFO // mode, but we check for it anyway for completeness. (and to avoid validation warnings) VkPresentModeKHR const desiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; - FixedCapacityVector presentModes - = enumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, mPhysicalDevice, mSurface); + FixedCapacityVector presentModes = fvkutils::enumerate( + vkGetPhysicalDeviceSurfacePresentModesKHR, mPhysicalDevice, mSurface); bool foundSuitablePresentMode = false; for (VkPresentModeKHR mode: presentModes) { if (mode == desiredPresentMode) { @@ -251,7 +252,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateSwapchainKHR failed." << " error=" << static_cast(result); - mSwapChainBundle.colors = enumerate(vkGetSwapchainImagesKHR, mDevice, mSwapchain); + mSwapChainBundle.colors = fvkutils::enumerate(vkGetSwapchainImagesKHR, mDevice, mSwapchain); mSwapChainBundle.colorFormat = surfaceFormat.format; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil); @@ -329,7 +330,7 @@ bool VulkanPlatformSurfaceSwapChain::hasResized() { || perceivedExtent.height == VULKAN_UNDEFINED_EXTENT) { perceivedExtent = mFallbackExtent; } - return !equivalent(mSwapChainBundle.extent, perceivedExtent); + return !fvkutils::equivalent(mSwapChainBundle.extent, perceivedExtent); } bool VulkanPlatformSurfaceSwapChain::isProtected() { diff --git a/filament/backend/src/vulkan/VulkanUtility.cpp b/filament/backend/src/vulkan/utils/Conversion.cpp similarity index 92% rename from filament/backend/src/vulkan/VulkanUtility.cpp rename to filament/backend/src/vulkan/utils/Conversion.cpp index 889e2bdd2f35..1d1f9d1c0f1c 100644 --- a/filament/backend/src/vulkan/VulkanUtility.cpp +++ b/filament/backend/src/vulkan/utils/Conversion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,13 @@ * limitations under the License. */ -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" -#include -#include #include #include "private/backend/BackendUtils.h" -using namespace bluevk; - -namespace filament::backend { +namespace filament::backend::fvkutils { VkFormat getVkFormat(ElementType type, bool normalized, bool integer) { using ElementType = ElementType; @@ -235,12 +231,6 @@ VkFormat getVkFormat(TextureFormat format) { } } -// Converts PixelBufferDescriptor format + type pair into a VkFormat. -// -// NOTE: This function only returns formats that support VK_FORMAT_FEATURE_BLIT_SRC_BIT as per -// "Required Format Support" in the Vulkan specification. These are the only formats that can be -// used for format conversion. If the requested format does not support this feature, then -// VK_FORMAT_UNDEFINED is returned. VkFormat getVkFormat(PixelDataFormat format, PixelDataType type) { if (type == PixelDataType::USHORT_565) return VK_FORMAT_R5G6B5_UNORM_PACK16; if (type == PixelDataType::UINT_2_10_10_10_REV) return VK_FORMAT_A2B10G10R10_UNORM_PACK32; @@ -284,10 +274,6 @@ VkFormat getVkFormat(PixelDataFormat format, PixelDataType type) { return VK_FORMAT_UNDEFINED; } -// Converts an SRGB Vulkan format identifier into its corresponding canonical UNORM format. If the -// given format is not an SRGB format, it is returned unmodified. This function is useful when -// determining if blit-based conversion is needed, since SRGB is orthogonal to the actual bit layout -// of color components. VkFormat getVkFormatLinear(VkFormat format) { switch (format) { case VK_FORMAT_R8_SRGB: return VK_FORMAT_R8_UNORM; @@ -328,8 +314,6 @@ VkFormat getVkFormatLinear(VkFormat format) { return format; } -// See also FTexture::computeTextureDataSize, which takes a public-facing Texture format rather -// than a driver-level Texture format, and can account for a specified byte alignment. uint32_t getBytesPerPixel(TextureFormat format) { return (uint32_t) getFormatSize(format); } @@ -611,48 +595,4 @@ VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) { return flags; } -bool equivalent(const VkRect2D& a, const VkRect2D& b) { - // These are all integers so there's no need for an epsilon. - return a.extent.width == b.extent.width && a.extent.height == b.extent.height && - a.offset.x == b.offset.x && a.offset.y == b.offset.y; -} - -bool equivalent(const VkExtent2D& a, const VkExtent2D& b) { - return a.height == b.height && a.width == b.width; -} - -VkImageAspectFlags getImageAspect(VkFormat format) { - switch (format) { - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_X8_D24_UNORM_PACK32: - case VK_FORMAT_D32_SFLOAT: - return VK_IMAGE_ASPECT_DEPTH_BIT; - case VK_FORMAT_S8_UINT: - return VK_IMAGE_ASPECT_STENCIL_BIT; - default: - return VK_IMAGE_ASPECT_COLOR_BIT; - } -} - -bool isVkDepthFormat(VkFormat format) { - return (getImageAspect(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; -} - -bool isVkStencilFormat(VkFormat format) { - return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; -} - -static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); } - -uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) { - if (sampleCount & mask) { - return sampleCount; - } - return mostSignificantBit((sampleCount - 1) & mask); -} - -} // namespace filament::backend +} // namespace filament::backend::fvkutils diff --git a/filament/backend/src/vulkan/utils/Conversion.h b/filament/backend/src/vulkan/utils/Conversion.h new file mode 100644 index 000000000000..10f5b5ad0d97 --- /dev/null +++ b/filament/backend/src/vulkan/utils/Conversion.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H + +#include + +#include // for getFormatSize() + +#include + +// Methods for converting Filament types to Vulkan types + +namespace filament::backend::fvkutils { + +VkFormat getVkFormat(ElementType type, bool normalized, bool integer); +VkFormat getVkFormat(TextureFormat format); + +// Converts PixelBufferDescriptor format + type pair into a VkFormat. +// NOTE: This function only returns formats that support VK_FORMAT_FEATURE_BLIT_SRC_BIT as per +// "Required Format Support" in the Vulkan specification. These are the only formats that can be +// used for format conversion. If the requested format does not support this feature, then +// VK_FORMAT_UNDEFINED is returned. +VkFormat getVkFormat(PixelDataFormat format, PixelDataType type); + +// Converts an SRGB Vulkan format identifier into its corresponding canonical UNORM format. If the +// given format is not an SRGB format, it is returned unmodified. This function is useful when +// determining if blit-based conversion is needed, since SRGB is orthogonal to the actual bit layout +// of color components. +VkFormat getVkFormatLinear(VkFormat format); + +// See also FTexture::computeTextureDataSize, which takes a public-facing Texture format rather +// than a driver-level Texture format, and can account for a specified byte alignment. +uint32_t getBytesPerPixel(TextureFormat format); + +VkCompareOp getCompareOp(SamplerCompareFunc func); +VkBlendFactor getBlendFactor(BlendFunction mode); +VkCullModeFlags getCullMode(CullingMode mode); +VkFrontFace getFrontFace(bool inverseFrontFaces); +PixelDataType getComponentType(VkFormat format); +uint32_t getComponentCount(VkFormat format); +VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]); +VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags); + +inline VkImageViewType getViewType(SamplerType target) { + switch (target) { + case SamplerType::SAMPLER_CUBEMAP: + return VK_IMAGE_VIEW_TYPE_CUBE; + case SamplerType::SAMPLER_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case SamplerType::SAMPLER_CUBEMAP_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + case SamplerType::SAMPLER_3D: + return VK_IMAGE_VIEW_TYPE_3D; + default: + return VK_IMAGE_VIEW_TYPE_2D; + } +} + +}// namespace filament::backend::fvkutils + +#endif// TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H diff --git a/filament/backend/src/vulkan/VulkanUtility.h b/filament/backend/src/vulkan/utils/Definitions.h similarity index 70% rename from filament/backend/src/vulkan/VulkanUtility.h rename to filament/backend/src/vulkan/utils/Definitions.h index 33be80d3fa8e..157eb4c40fa9 100644 --- a/filament/backend/src/vulkan/VulkanUtility.h +++ b/filament/backend/src/vulkan/utils/Definitions.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * -* Licensed under the Apache License, Version 2.0 (the "License"); + * 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 * @@ -14,82 +14,17 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANUTILITY_H -#define TNT_FILAMENT_BACKEND_VULKANUTILITY_H - -#include +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H #include #include #include -#include - -namespace filament::backend { - -VkFormat getVkFormat(ElementType type, bool normalized, bool integer); -VkFormat getVkFormat(TextureFormat format); -VkFormat getVkFormat(PixelDataFormat format, PixelDataType type); -VkFormat getVkFormatLinear(VkFormat format); -uint32_t getBytesPerPixel(TextureFormat format); -VkCompareOp getCompareOp(SamplerCompareFunc func); -VkBlendFactor getBlendFactor(BlendFunction mode); -VkCullModeFlags getCullMode(CullingMode mode); -VkFrontFace getFrontFace(bool inverseFrontFaces); -PixelDataType getComponentType(VkFormat format); -uint32_t getComponentCount(VkFormat format); -VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]); -VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags); - -bool equivalent(const VkRect2D& a, const VkRect2D& b); -bool equivalent(const VkExtent2D& a, const VkExtent2D& b); -bool isVkDepthFormat(VkFormat format); -bool isVkStencilFormat(VkFormat format); - -VkImageAspectFlags getImageAspect(VkFormat format); -uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask); - -// Helper function for the vkEnumerateX methods. These methods have the format of -// VkResult vkEnumerateX(InputType1 arg1, InputTyp2 arg2, ..., uint32_t* size, -// OutputType* output_arg) -// Instead of macros and explicitly listing the template params, Variadic Template was also -// considered, but because the "variadic" part of the vk methods (i.e. the inputs) are before the -// non-variadic parts, this breaks the template type matching logic. Hence, we use a macro approach -// here. -#define EXPAND_ENUM(...) \ - uint32_t size = 0; \ - VkResult result = func(__VA_ARGS__, nullptr); \ - FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate size error"; \ - utils::FixedCapacityVector ret(size); \ - result = func(__VA_ARGS__, ret.data()); \ - FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate error"; \ - return std::move(ret); - -#define EXPAND_ENUM_NO_ARGS() EXPAND_ENUM(&size) -#define EXPAND_ENUM_ARGS(...) EXPAND_ENUM(__VA_ARGS__, &size) - -template -utils::FixedCapacityVector enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) { - EXPAND_ENUM_NO_ARGS(); -} - -template -utils::FixedCapacityVector enumerate( - VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) { - EXPAND_ENUM_ARGS(inData); -} - -template -utils::FixedCapacityVector enumerate( - VKAPI_ATTR VkResult (*func)(InTypeA, InTypeB, uint32_t*, OutType*), InTypeA inDataA, - InTypeB inDataB) { - EXPAND_ENUM_ARGS(inDataA, inDataB); -} +// Definitions for common types used across classes. -#undef EXPAND_ENUM -#undef EXPAND_ENUM_NO_ARGS -#undef EXPAND_ENUM_ARGS +namespace filament::backend::fvkutils { // Useful shorthands using VkFormatList = utils::FixedCapacityVector; @@ -406,128 +341,6 @@ constexpr VkFormat ALL_VK_FORMATS[] = { VK_FORMAT_R16G16_S10_5_NV, }; -// An Array that will be statically fixed in capacity, but the "size" (as in user added elements) is -// variable. Note that this class is movable. -template -class CappedArray { -private: - using FixedSizeArray = std::array; - -public: - using const_iterator = typename FixedSizeArray::const_iterator; - using iterator = typename FixedSizeArray::iterator; - - CappedArray() = default; - - // Delete copy constructor/assignment. - CappedArray(CappedArray const& rhs) = delete; - CappedArray& operator=(CappedArray& rhs) = delete; - - CappedArray(CappedArray&& rhs) noexcept { - this->swap(rhs); - } - - CappedArray& operator=(CappedArray&& rhs) noexcept { - this->swap(rhs); - return *this; - } - - inline ~CappedArray() { - clear(); - } - - inline const_iterator begin() const { - if (mInd == 0) { - return mArray.cend(); - } - return mArray.cbegin(); - } - - inline const_iterator end() const { - if (mInd > 0 && mInd < CAPACITY) { - return mArray.begin() + mInd; - } - return mArray.cend(); - } - - inline iterator begin() { - if (mInd == 0) { - return mArray.end(); - } - return mArray.begin(); - } - - inline iterator end() { - if (mInd > 0 && mInd < CAPACITY) { - return mArray.begin() + mInd; - } - return mArray.end(); - } - - inline T back() { - assert_invariant(mInd > 0); - return *(mArray.begin() + mInd); - } - - inline void pop_back() { - assert_invariant(mInd > 0); - mInd--; - } - - inline const_iterator find(T item) { - return std::find(begin(), end(), item); - } - - inline void insert(T item) { - assert_invariant(mInd < CAPACITY); - mArray[mInd++] = item; - } - - inline void erase(T item) { - PANIC_PRECONDITION("CappedArray::erase should not be called"); - } - - inline void clear() { - if (mInd == 0) { - return; - } - mInd = 0; - } - - inline T& operator[](uint16_t ind) { - return mArray[ind]; - } - - inline T const& operator[](uint16_t ind) const { - return mArray[ind]; - } - - inline uint32_t size() const { - return mInd; - } - - T* data() { - return mArray.data(); - } - - T const* data() const { - return mArray.data(); - } - - bool operator==(CappedArray const& b) const { - return this->mArray == b.mArray; - } - -private: - void swap(CappedArray& rhs) { - std::swap(mArray, rhs.mArray); - std::swap(mInd, rhs.mInd); - } - - FixedSizeArray mArray; - uint32_t mInd = 0; -}; - using UniformBufferBitmask = utils::bitset64; using SamplerBitmask = utils::bitset64; @@ -550,7 +363,6 @@ static constexpr uint8_t getFragmentStageShift() noexcept { // We have at most 4 descriptor sets. This is to indicate which ones are active. using DescriptorSetMask = utils::bitset8; +} // namespace filament::backend::fvkutils -} // namespace filament::backend - -#endif // TNT_FILAMENT_BACKEND_VULKANUTILITY_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H diff --git a/filament/backend/src/vulkan/utils/Helper.h b/filament/backend/src/vulkan/utils/Helper.h new file mode 100644 index 000000000000..0ae3cf5a1cde --- /dev/null +++ b/filament/backend/src/vulkan/utils/Helper.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * +* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_HELPER_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_HELPER_H + +#include + +#include +#include + +#include + +#include + +namespace filament::backend::fvkutils { + +inline bool equivalent(const VkRect2D& a, const VkRect2D& b) { + // These are all integers so there's no need for an epsilon. + return a.extent.width == b.extent.width && a.extent.height == b.extent.height && + a.offset.x == b.offset.x && a.offset.y == b.offset.y; +} + +inline bool equivalent(const VkExtent2D& a, const VkExtent2D& b) { + return a.height == b.height && a.width == b.width; +} + +// Helper function for the vkEnumerateX methods. These methods have the format of +// VkResult vkEnumerateX(InputType1 arg1, InputTyp2 arg2, ..., uint32_t* size, +// OutputType* output_arg) +// Instead of macros and explicitly listing the template params, Variadic Template was also +// considered, but because the "variadic" part of the vk methods (i.e. the inputs) are before the +// non-variadic parts, this breaks the template type matching logic. Hence, we use a macro approach +// here. +#define EXPAND_ENUM(...) \ + uint32_t size = 0; \ + VkResult result = func(__VA_ARGS__, nullptr); \ + FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate size error"; \ + utils::FixedCapacityVector ret(size); \ + result = func(__VA_ARGS__, ret.data()); \ + FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate error"; \ + return std::move(ret); + +#define EXPAND_ENUM_NO_ARGS() EXPAND_ENUM(&size) +#define EXPAND_ENUM_ARGS(...) EXPAND_ENUM(__VA_ARGS__, &size) + +template +utils::FixedCapacityVector enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) { + EXPAND_ENUM_NO_ARGS(); +} + +template +utils::FixedCapacityVector enumerate( + VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) { + EXPAND_ENUM_ARGS(inData); +} + +template +utils::FixedCapacityVector enumerate( + VKAPI_ATTR VkResult (*func)(InTypeA, InTypeB, uint32_t*, OutType*), InTypeA inDataA, + InTypeB inDataB) { + EXPAND_ENUM_ARGS(inDataA, inDataB); +} + +#undef EXPAND_ENUM +#undef EXPAND_ENUM_NO_ARGS +#undef EXPAND_ENUM_ARGS + +} // namespace filament::backend::fvkutils + +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_HELPER_H diff --git a/filament/backend/src/vulkan/VulkanImageUtility.cpp b/filament/backend/src/vulkan/utils/Image.cpp similarity index 87% rename from filament/backend/src/vulkan/VulkanImageUtility.cpp rename to filament/backend/src/vulkan/utils/Image.cpp index 415eb305cab2..fb160fc4b000 100644 --- a/filament/backend/src/vulkan/VulkanImageUtility.cpp +++ b/filament/backend/src/vulkan/utils/Image.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "VulkanImageUtility.h" +#include "vulkan/utils/Image.h" -#include "VulkanTexture.h" +#include "vulkan/VulkanTexture.h" #include #include @@ -26,7 +26,7 @@ using namespace bluevk; -namespace filament::backend::imgutil { +namespace filament::backend::fvkutils { namespace { @@ -159,7 +159,41 @@ bool transitionLayout(VkCommandBuffer cmdbuffer, return true; } -}// namespace filament::backend +VkImageAspectFlags getImageAspect(VkFormat format) { + switch (format) { + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case VK_FORMAT_S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } +} + +bool isVkDepthFormat(VkFormat format) { + return (getImageAspect(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; +} + +bool isVkStencilFormat(VkFormat format) { + return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; +} + +static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); } + +uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) { + if (sampleCount & mask) { + return sampleCount; + } + return mostSignificantBit((sampleCount - 1) & mask); +} + +} // namespace filament::backend::fvkutils bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& b) { if (a.aspectMask < b.aspectMask) return true; diff --git a/filament/backend/src/vulkan/VulkanImageUtility.h b/filament/backend/src/vulkan/utils/Image.h similarity index 84% rename from filament/backend/src/vulkan/VulkanImageUtility.h rename to filament/backend/src/vulkan/utils/Image.h index f8027d96975d..fcd57ee3310f 100644 --- a/filament/backend/src/vulkan/VulkanImageUtility.h +++ b/filament/backend/src/vulkan/utils/Image.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H -#define TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H #include @@ -59,22 +59,7 @@ struct VulkanLayoutTransition { VkImageSubresourceRange subresources; }; -namespace imgutil { - -inline VkImageViewType getViewType(SamplerType target) { - switch (target) { - case SamplerType::SAMPLER_CUBEMAP: - return VK_IMAGE_VIEW_TYPE_CUBE; - case SamplerType::SAMPLER_2D_ARRAY: - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - case SamplerType::SAMPLER_CUBEMAP_ARRAY: - return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - case SamplerType::SAMPLER_3D: - return VK_IMAGE_VIEW_TYPE_3D; - default: - return VK_IMAGE_VIEW_TYPE_2D; - } -} +namespace fvkutils { constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) { switch (layout) { @@ -109,7 +94,15 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) { // no transition necessary). bool transitionLayout(VkCommandBuffer cmdbuffer, VulkanLayoutTransition transition); -} // namespace imgutil +bool isVkDepthFormat(VkFormat format); + +bool isVkStencilFormat(VkFormat format); + +VkImageAspectFlags getImageAspect(VkFormat format); + +uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask); + +} // namespace fvkutils } // namespace filament::backend @@ -117,5 +110,4 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::VulkanLayout& layout); - -#endif // TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H diff --git a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp b/filament/backend/src/vulkan/utils/Spirv.cpp similarity index 72% rename from filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp rename to filament/backend/src/vulkan/utils/Spirv.cpp index 209745facd93..a1c5933dd0a0 100644 --- a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp +++ b/filament/backend/src/vulkan/utils/Spirv.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "VulkanSpirvUtils.h" +#include "vulkan/utils/Spirv.h" #include // UTILS_UNUSED_IN_RELEASE, UTILS_FALLTHROUGH #include // assert_invariant @@ -22,12 +22,11 @@ #include +#include #include -#include #include -#include -namespace filament::backend { +namespace filament::backend::fvkutils { namespace { @@ -99,7 +98,7 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, uint32_t const* data = (uint32_t*) blob.data(); uint32_t* outputData = output.data(); - std::memcpy(&outputData[0], &data[0], HEADER_SIZE * 4); + memcpy(&outputData[0], &data[0], HEADER_SIZE * 4); size_t outputCursor = HEADER_SIZE; for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) { @@ -147,61 +146,4 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, output.resize(outputCursor); } -std::tuple getProgramBindings(Program::ShaderBlob const& blob) { - std::unordered_map targetToSet, targetToBinding; - - constexpr size_t HEADER_SIZE = 5; - - size_t const dataSize = blob.size() / 4; - uint32_t const* data = (uint32_t*) blob.data(); - - for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) { - uint32_t const firstWord = data[cursor]; - uint32_t const wordCount = firstWord >> 16; - uint32_t const op = firstWord & 0x0000FFFF; - - switch(op) { - case spv::Op::OpDecorate: { - if (data[cursor + 2] == spv::Decoration::DecorationDescriptorSet) { - uint32_t const targetVar = data[cursor + 1]; - uint32_t const setId = data[cursor + 3]; - targetToSet[targetVar] = setId; - } else if (data[cursor + 2] == spv::Decoration::DecorationBinding) { - uint32_t const targetVar = data[cursor + 1]; - uint32_t const binding = data[cursor + 3]; - targetToBinding[targetVar] = binding; - } - break; - } - default: - break; - } - cursor += wordCount; - } - - constexpr uint32_t UBO = 0; - constexpr uint32_t SAMPLER = 1; - constexpr uint32_t IATTACHMENT = 2; - uint32_t ubo = 0, sampler = 0, inputAttachment = 0; - - for (auto const& [target, setId]: targetToSet) { - uint32_t const binding = targetToBinding[target]; - assert_invariant(binding < 32); - switch(setId) { - case UBO: - ubo |= (1 << binding); - break; - case SAMPLER: - sampler |= (1 << binding); - break; - case IATTACHMENT: - inputAttachment |= (1 << binding); - break; - default: - PANIC_POSTCONDITION("unexpected %d", (int) setId); - } - } - return {ubo, sampler, inputAttachment}; -} - -} // namespace filament::backend +} // namespace filament::backend::fvkutils diff --git a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h b/filament/backend/src/vulkan/utils/Spirv.h similarity index 77% rename from filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h rename to filament/backend/src/vulkan/utils/Spirv.h index 2a9f79a6118e..941c30a32d68 100644 --- a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h +++ b/filament/backend/src/vulkan/utils/Spirv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H -#define TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H #include @@ -24,7 +24,7 @@ #include #include -namespace filament::backend { +namespace filament::backend::fvkutils { using SpecConstantValue = Program::SpecializationConstant::Type; @@ -44,8 +44,9 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, std::vector& output); // bindings for UBO, samplers, input attachment -std::tuple getProgramBindings(Program::ShaderBlob const& blob); +// This is no longer needed after the descriptor set refactor, but the code is good for reference. +// std::tuple getProgramBindings(Program::ShaderBlob const& blob); -} // namespace filament::backend +} // namespace filament::backend::fvkutils -#endif // TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H diff --git a/filament/backend/src/vulkan/utils/StaticVector.h b/filament/backend/src/vulkan/utils/StaticVector.h new file mode 100644 index 000000000000..b9abf8f9f2f1 --- /dev/null +++ b/filament/backend/src/vulkan/utils/StaticVector.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * +* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_STATICVECTOR_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_STATICVECTOR_H + +// An Array that will be statically fixed in capacity, but the "size" (as in user added elements) is +// variable. Note that this class is movable. + +#include + +#include + +namespace filament::backend::fvkutils { + +template +class StaticVector { +private: + using FixedSizeArray = std::array; + + static_assert(CAPACITY <= (1LL << (8 * sizeof(uint16_t)))); + +public: + using const_iterator = typename FixedSizeArray::const_iterator; + using iterator = typename FixedSizeArray::iterator; + + StaticVector() = default; + + // Delete copy constructor/assignment. + StaticVector(StaticVector const& rhs) = delete; + StaticVector& operator=(StaticVector& rhs) = delete; + + StaticVector(StaticVector&& rhs) noexcept { + std::swap(mSize, rhs.mSize); + std::swap(mArray, rhs.mArray); + } + + StaticVector& operator=(StaticVector&& rhs) noexcept { + std::swap(mSize, rhs.mSize); + std::swap(mArray, rhs.mArray); + return *this; + } + + inline ~StaticVector() { + clear(); + } + + inline const_iterator begin() const { + return mArray.cbegin(); + } + + inline const_iterator end() const { + assert_invariant(mSize <= CAPACITY); + return mArray.begin() + mSize; + } + + inline iterator begin() { + return mArray.begin(); + } + + inline iterator end() { + assert_invariant(mSize <= CAPACITY); + return mArray.begin() + mSize; + } + + inline T back() { + assert_invariant(mSize > 0); + return *(mArray.begin() + mSize); + } + + inline void pop_back() { + assert_invariant(mSize > 0); + mSize--; + } + + inline const_iterator find(T item) { + return std::find(begin(), end(), item); + } + + inline void push_back(T item) { + assert_invariant(mSize < CAPACITY); + mArray[mSize++] = item; + } + + inline void clear() { + mSize = 0; + } + + inline T& operator[](size_t index) { + assert_invariant(index < mSize); + return mArray[index]; + } + + inline T const& operator[](size_t index) const { + return mArray[index]; + } + + inline uint16_t size() const { + return mSize; + } + + T* data() { + return mArray.data(); + } + + T const* data() const { + return mArray.data(); + } + + bool operator==(StaticVector const& b) const { + return this->mArray == b.mArray && this->mSize == b.mSize; + } + +private: + FixedSizeArray mArray; + uint16_t mSize = 0; +}; + +} // namespace filament::backend::fvkutils + +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_STATICVECTOR_H diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 5092e16c385b..d28f836b0eb7 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -17,6 +17,7 @@ #ifndef TNT_FILAMENT_ENGINE_H #define TNT_FILAMENT_ENGINE_H + #include #include @@ -32,6 +33,7 @@ #include #include + namespace utils { class Entity; class EntityManager; @@ -40,6 +42,10 @@ class JobSystem; namespace filament { +namespace backend { +class Driver; +} // backend + class BufferObject; class Camera; class ColorGrading; @@ -183,6 +189,7 @@ class UTILS_PUBLIC Engine { using DriverConfig = backend::Platform::DriverConfig; using FeatureLevel = backend::FeatureLevel; using StereoscopicType = backend::StereoscopicType; + using Driver = backend::Driver; /** * Config is used to define the memory footprint used by the engine, such as the @@ -310,6 +317,15 @@ class UTILS_PUBLIC Engine { */ size_t metalUploadBufferSizeBytes = 512 * 1024; + /** + * The action to take if a Drawable cannot be acquired. + * + * Each frame rendered requires a CAMetalDrawable texture, which is + * presented on-screen at the completion of each frame. These are + * limited and provided round-robin style by the system. + */ + bool metalDisablePanicOnDrawableFailure = false; + /** * Set to `true` to forcibly disable parallel shader compilation in the backend. * Currently only honored by the GL and Metal backends. @@ -582,6 +598,11 @@ class UTILS_PUBLIC Engine { static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token); #endif + /** + * @return the Driver instance used by this Engine. + * @see OpenGLPlatform + */ + backend::Driver const* UTILS_NONNULL getDriver() const noexcept; /** * Destroy the Engine instance and all associated resources. diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index 12b28358a96c..62ab5094354c 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -23,6 +23,7 @@ #include #include +#include #include @@ -70,7 +71,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { struct BuilderDetails; public: - static constexpr const size_t BASE_LEVEL = 0; + static constexpr size_t BASE_LEVEL = 0; //! Face offsets for all faces of a cubemap struct FaceOffsets; @@ -84,14 +85,16 @@ class UTILS_PUBLIC Texture : public FilamentAPI { using CompressedType = backend::CompressedPixelDataType; //!< Compressed pixel data format using Usage = backend::TextureUsage; //!< Usage affects texel layout using Swizzle = backend::TextureSwizzle; //!< Texture swizzle + using ExternalImageHandle = backend::Platform::ExternalImageHandle; + using ExternalImageHandleRef = backend::Platform::ExternalImageHandleRef; - /** @return whether a backend supports a particular format. */ + /** @return Whether a backend supports a particular format. */ static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept; - /** @return whether this backend supports protected textures. */ + /** @return Whether this backend supports protected textures. */ static bool isProtectedTexturesSupported(Engine& engine) noexcept; - /** @return whether a backend supports texture swizzling. */ + /** @return Whether a backend supports texture swizzling. */ static bool isTextureSwizzleSupported(Engine& engine) noexcept; static size_t computeTextureDataSize(Format format, Type type, @@ -217,6 +220,18 @@ class UTILS_PUBLIC Texture : public FilamentAPI { */ Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * + * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. + * + * @return + */ + Builder& external() noexcept; + /** * Creates the Texture object and returns a pointer to it. * @@ -261,18 +276,6 @@ class UTILS_PUBLIC Texture : public FilamentAPI { */ Builder& import(intptr_t id) noexcept; - /** - * Creates an external texture. The content must be set using setExternalImage(). - * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally - * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not - * validated. - * - * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. - * - * @return - */ - Builder& external() noexcept; - private: friend class FTexture; }; @@ -359,7 +362,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { * uint32_t width, uint32_t height, uint32_t depth, * PixelBufferDescriptor&& buffer) */ - inline void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { + void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { setImage(engine, level, 0, 0, 0, uint32_t(getWidth(level)), uint32_t(getHeight(level)), 1, std::move(buffer)); } @@ -372,7 +375,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { * uint32_t width, uint32_t height, uint32_t depth, * PixelBufferDescriptor&& buffer) */ - inline void setImage(Engine& engine, size_t level, + void setImage(Engine& engine, size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& buffer) const { setImage(engine, level, xoffset, yoffset, 0, width, height, 1, std::move(buffer)); @@ -406,6 +409,26 @@ class UTILS_PUBLIC Texture : public FilamentAPI { PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; + /** + * Specify the external image to associate with this Texture. Typically, the external + * image is OS specific, and can be a video or camera frame. + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. It must be created using Platform + * specific APIs. For example PlatformEGL::createExternalImage(EGLImageKHR eglImage) + * + * @see PlatformEGL::createExternalImage + * @see PlatformEGLAndroid::createExternalImage + * @see PlatformCocoaGL::createExternalImage + * @see PlatformCocoaTouchGL::createExternalImage + */ + void setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept; + /** * Specify the external image to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. @@ -428,7 +451,9 @@ class UTILS_PUBLIC Texture : public FilamentAPI { * * @see Builder::sampler() * + * @deprecated Instead, use setExternalImage(Engine& engine, ExternalImageHandleRef image) */ + UTILS_DEPRECATED void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; /** @@ -463,7 +488,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane) noexcept; /** - * Specify the external stream to associate with this Texture. Typically the external + * Specify the external stream to associate with this Texture. Typically, the external * stream is OS specific, and can be a video or camera stream. * There are many restrictions when using an external stream as a texture, such as: * - only the level of detail (lod) 0 can be specified @@ -474,7 +499,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { * @param stream A Stream object * * @attention \p engine must be the instance passed to Builder::build() - * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL, or it has no effect * * @see Builder::sampler(), Stream * @@ -522,9 +547,9 @@ class UTILS_PUBLIC Texture : public FilamentAPI { * @param buffer Client-side buffer containing the images to set. * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets * are specified in the following order: +x, -x, +y, -y, +z, -z - * @param options Optional parameter to controlling user-specified quality and options. + * @param options Optional parameter controlling user-specified quality and options. * - * @exception utils::PreConditionPanic if the source data constraints are not respected. + * @exception utils::PreConditionPanic If the source data constraints are not respected. * */ void generatePrefilterMipmap(Engine& engine, diff --git a/filament/src/Culler.cpp b/filament/src/Culler.cpp index 85e8bf03ac40..0fb5358e03ed 100644 --- a/filament/src/Culler.cpp +++ b/filament/src/Culler.cpp @@ -40,12 +40,16 @@ void Culler::intersects( float4 const * const UTILS_RESTRICT planes = frustum.mPlanes; count = round(count); +#if defined(__clang__) #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) +#endif for (size_t i = 0; i < count; i++) { int visible = ~0; float4 const sphere(b[i]); +#if defined(__clang__) #pragma clang loop unroll(full) +#endif for (size_t j = 0; j < 6; j++) { // clang doesn't seem to generate vector * scalar instructions, which leads // to increased register pressure and stack spills @@ -69,11 +73,15 @@ void Culler::intersects( float4 const * UTILS_RESTRICT const planes = frustum.mPlanes; count = round(count); +#if defined(__clang__) #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) +#endif for (size_t i = 0; i < count; i++) { int visible = ~0; +#if defined(__clang__) #pragma clang loop unroll(full) +#endif for (size_t j = 0; j < 6; j++) { // clang doesn't seem to generate vector * scalar instructions, which leads // to increased register pressure and stack spills diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index 455067739ce3..1927e7a34fe2 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -68,6 +68,10 @@ Engine* Engine::getEngine(void* token) { } #endif +Driver const* Engine::getDriver() const noexcept { + return std::addressof(downcast(this)->getDriver()); +} + void Engine::destroy(Engine** pEngine) { if (pEngine) { Engine* engine = *pEngine; diff --git a/filament/src/Froxelizer.cpp b/filament/src/Froxelizer.cpp index fe8975276ecf..0feed6571769 100644 --- a/filament/src/Froxelizer.cpp +++ b/filament/src/Froxelizer.cpp @@ -395,7 +395,9 @@ bool Froxelizer::update() noexcept { const float linearizer = std::log2(zLightFar / zLightNear) / float(std::max(1u, mFroxelCountZ - 1u)); // for a strange reason when, vectorizing this loop, clang does some math in double // and generates conversions to float. not worth it for so little iterations. +#if defined(__clang__) #pragma clang loop vectorize(disable) unroll(disable) +#endif for (ssize_t i = 1, n = mFroxelCountZ; i <= n; i++) { mDistancesZ[i] = zLightFar * std::exp2(float(i - n) * linearizer); } diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index d9ab8b0c1664..469c0122ede3 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -2661,7 +2661,7 @@ void PostProcessManager::TaaJitterCamera( // update projection matrix inoutCameraInfo->projection[2].xy -= jitterInClipSpace; // VERTEX_DOMAIN_DEVICE doesn't apply the projection, but it still needs this - // clip transform, so we apply it separately (see main.vs) + // clip transform, so we apply it separately (see surface_main.vs) inoutCameraInfo->clipTransform.zw -= jitterInClipSpace; } diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index b71345458d6c..4985c8ff086f 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -253,7 +253,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine, // The model matrix below is in fact inverted to get the view matrix and passed to the // shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric. - // (see depth_main.fs). Note that in the case of VSM, 'b' below is identity. + // (see surface_depth_main.fs). Note that in the case of VSM, 'b' below is identity. mCamera->setModelMatrix(FCamera::rigidTransformInverse(highPrecisionMultiplyd(Mv, b))); mCamera->setCustomProjection(mat4(Mn * F * WLMp), znear, zfar); @@ -315,7 +315,7 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual( // The model matrix below is in fact inverted to get the view matrix and passed to the // shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric. - // (see depth_main.fs). Note that in the case of VSM, 'b' below is identity. + // (see surface_depth_main.fs). Note that in the case of VSM, 'b' below is identity. mCamera->setModelMatrix(FCamera::rigidTransformInverse(highPrecisionMultiplyd(Mv, b))); mCamera->setCustomProjection(highPrecisionMultiplyd(Mn, Mp), nearPlane, farPlane); @@ -719,7 +719,7 @@ mat4f ShadowMap::computeVsmLightSpaceMatrix(const mat4f& lightSpacePcf, // For VSM, we want to leave the z coordinate in linear light-space, normalized between [0, 1], // i.e. remapping [near, far] to [0, 1]. // When sampling a VSM shadow map, the shader follows suit, and doesn't divide by w for the z - // coordinate. See shadowing.fs. + // coordinate. See surface_shadowing.fs. // compute z' = -(Mv * position).z / (far - near) - (near / (far - near)) const float scale = 1.0f / (zfar - znear); mat4f lightSpaceVsm{ lightSpacePcf }; diff --git a/filament/src/Texture.cpp b/filament/src/Texture.cpp index eb67f5b43cf4..d3f53e8ea94f 100644 --- a/filament/src/Texture.cpp +++ b/filament/src/Texture.cpp @@ -58,6 +58,10 @@ void Texture::setImage(Engine& engine, size_t const level, downcast(this)->setImage(downcast(engine), level, std::move(buffer), faceOffsets); } +void Texture::setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept { + downcast(this)->setExternalImage(downcast(engine), image); +} + void Texture::setExternalImage(Engine& engine, void* image) noexcept { downcast(this)->setExternalImage(downcast(engine), image); } diff --git a/filament/src/ToneMapper.cpp b/filament/src/ToneMapper.cpp index e6f9fc8c1459..5c4203dae3a1 100644 --- a/filament/src/ToneMapper.cpp +++ b/filament/src/ToneMapper.cpp @@ -399,8 +399,10 @@ float3 DisplayRangeToneMapper::operator()(float3 const c) const noexcept { //------------------------------------------------------------------------------ struct GenericToneMapper::Options { +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wshadow" +#endif void setParameters( float contrast, float midGrayIn, @@ -424,7 +426,9 @@ struct GenericToneMapper::Options { inputScale = (a * b * (midGrayOut - 1.0f)) / c; outputScale = midGrayOut * (a - b) / c; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif float contrast; float midGrayIn; diff --git a/filament/src/details/ColorGrading.cpp b/filament/src/details/ColorGrading.cpp index b3c577c2d661..a1077f771bdc 100644 --- a/filament/src/details/ColorGrading.cpp +++ b/filament/src/details/ColorGrading.cpp @@ -52,10 +52,14 @@ using namespace backend; struct ColorGrading::BuilderDetails { const ToneMapper* toneMapper = nullptr; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif ToneMapping toneMapping = ToneMapping::ACES_LEGACY; +#if defined(__clang__) #pragma clang diagnostic pop +#endif bool hasAdjustments = false; @@ -268,8 +272,10 @@ ColorGrading::Builder& ColorGrading::Builder::outputColorSpace( return *this; } +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif ColorGrading* ColorGrading::Builder::build(Engine& engine) { // We want to see if any of the default adjustment values have been modified // We skip the tonemapping operator on purpose since we always want to apply it @@ -309,7 +315,9 @@ ColorGrading* ColorGrading::Builder::build(Engine& engine) { return colorGrading; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif //------------------------------------------------------------------------------ // Exposure @@ -585,8 +593,10 @@ static std::tuple } } +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // The following functions exist to preserve backward compatibility with the // `FILMIC` set via the deprecated `ToneMapping` API. Selecting `ToneMapping::FILMIC` // forces post-processing to be performed in sRGB to guarantee that the inverse tone @@ -612,7 +622,9 @@ static float3 selectColorGradingLuminance(ColorGrading::ToneMapping const toneMa } return LUMINANCE_Rec2020; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif using ColorTransform = float3(*)(float3); @@ -792,7 +804,9 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) { // 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) +#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)); diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 2116fae4c1b6..c6b4d67de8f7 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -123,6 +123,7 @@ Engine* FEngine::create(Builder const& builder) { .forceGLES2Context = instance->getConfig().forceGLES2Context, .stereoscopicType = instance->getConfig().stereoscopicType, .assertNativeWindowIsValid = instance->features.backend.opengl.assert_native_window_is_valid, + .metalDisablePanicOnDrawableFailure = instance->getConfig().metalDisablePanicOnDrawableFailure, }; instance->mDriver = platform->createDriver(sharedContext, driverConfig); @@ -706,6 +707,28 @@ int FEngine::loop() { } } + JobSystem::setThreadName("FEngine::loop"); + JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY); + + DriverConfig const driverConfig { + .handleArenaSize = getRequestedDriverHandleArenaSize(), + .metalUploadBufferSizeBytes = mConfig.metalUploadBufferSizeBytes, + .disableParallelShaderCompile = features.backend.disable_parallel_shader_compile, + .disableHandleUseAfterFreeCheck = features.backend.disable_handle_use_after_free_check, + .forceGLES2Context = mConfig.forceGLES2Context, + .stereoscopicType = mConfig.stereoscopicType, + .assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid, + .metalDisablePanicOnDrawableFailure = mConfig.metalDisablePanicOnDrawableFailure, + }; + mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig); + + mDriverBarrier.latch(); + if (UTILS_UNLIKELY(!mDriver)) { + // if we get here, it's because the driver couldn't be initialized and the problem has + // been logged. + return 0; + } + #if FILAMENT_ENABLE_MATDBG #ifdef __ANDROID__ const char* portString = "8081"; @@ -714,7 +737,7 @@ int FEngine::loop() { #endif if (portString != nullptr) { const int port = atoi(portString); - debug.server = new matdbg::DebugServer(mBackend, port); + debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), port); // Sometimes the server can fail to spin up (e.g. if the above port is already in use). // When this occurs, carry onward, developers can look at civetweb.txt for details. @@ -728,26 +751,24 @@ int FEngine::loop() { } #endif - JobSystem::setThreadName("FEngine::loop"); - JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY); - - DriverConfig const driverConfig { - .handleArenaSize = getRequestedDriverHandleArenaSize(), - .metalUploadBufferSizeBytes = mConfig.metalUploadBufferSizeBytes, - .disableParallelShaderCompile = features.backend.disable_parallel_shader_compile, - .disableHandleUseAfterFreeCheck = features.backend.disable_handle_use_after_free_check, - .forceGLES2Context = mConfig.forceGLES2Context, - .stereoscopicType = mConfig.stereoscopicType, - .assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid, - }; - mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig); +#if FILAMENT_ENABLE_FGVIEWER +#ifdef __ANDROID__ + const char* fgviewerPortString = "8085"; +#else + const char* fgviewerPortString = getenv("FILAMENT_FGVIEWER_PORT"); +#endif + if (fgviewerPortString != nullptr) { + const int fgviewerPort = atoi(fgviewerPortString); + debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort); - mDriverBarrier.latch(); - if (UTILS_UNLIKELY(!mDriver)) { - // if we get here, it's because the driver couldn't be initialized and the problem has - // been logged. - return 0; + // Sometimes the server can fail to spin up (e.g. if the above port is already in use). + // When this occurs, carry onward, developers can look at civetweb.txt for details. + if (!debug.fgviewerServer->isReady()) { + delete debug.fgviewerServer; + debug.fgviewerServer = nullptr; + } } +#endif while (true) { if (!execute()) { diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index a59b66c1c26e..eec73eba9533 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -61,6 +61,8 @@ #include #include +#include + #include #include #include @@ -88,6 +90,14 @@ using MaterialKey = uint32_t; } // namespace filament::matdbg #endif +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + class DebugServer; +} // namespace filament::fgviewer +#endif + namespace filament { class Renderer; @@ -114,12 +124,11 @@ class ResourceAllocator; */ class FEngine : public Engine { public: - - inline void* operator new(std::size_t const size) noexcept { + void* operator new(std::size_t const size) noexcept { return utils::aligned_alloc(size, alignof(FEngine)); } - inline void operator delete(void* p) noexcept { + void operator delete(void* p) noexcept { utils::aligned_free(p); } @@ -252,20 +261,12 @@ class FEngine : public Engine { // Return a vector of shader languages, in order of preference. utils::FixedCapacityVector getShaderLanguage() const noexcept { switch (mBackend) { - case Backend::DEFAULT: - case Backend::NOOP: default: - return { backend::ShaderLanguage::ESSL3 }; - case Backend::OPENGL: - return { getDriver().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0 - ? backend::ShaderLanguage::ESSL1 - : backend::ShaderLanguage::ESSL3 }; - case Backend::VULKAN: - return { backend::ShaderLanguage::SPIRV }; + return { getDriver().getShaderLanguage() }; case Backend::METAL: const auto& lang = mConfig.preferredShaderLanguage; if (lang == Config::ShaderLanguage::MSL) { - return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY }; + return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY}; } return { backend::ShaderLanguage::METAL_LIBRARY, backend::ShaderLanguage::MSL }; } @@ -490,7 +491,7 @@ class FEngine : public Engine { backend::Handle getOneTextureArray() const { return mDummyOneTextureArray; } backend::Handle getZeroTextureArray() const { return mDummyZeroTextureArray; } - static constexpr const size_t MiB = 1024u * 1024u; + static constexpr size_t MiB = 1024u * 1024u; size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; } size_t getCommandBufferSize() const noexcept { return mConfig.commandBufferSizeMB * MiB; } size_t getPerFrameCommandsSize() const noexcept { return mConfig.perFrameCommandsSizeMB * MiB; } @@ -510,6 +511,8 @@ class FEngine : public Engine { void resetBackendState() noexcept; #endif + backend::Driver& getDriver() const noexcept { return *mDriver; } + private: explicit FEngine(Builder const& builder); void init(); @@ -518,8 +521,6 @@ class FEngine : public Engine { int loop(); void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue); - backend::Driver& getDriver() const noexcept { return *mDriver; } - template bool isValid(const T* ptr, ResourceList const& list) const; @@ -681,6 +682,7 @@ class FEngine : public Engine { bool combine_multiview_images = false; } stereo; matdbg::DebugServer* server = nullptr; + fgviewer::DebugServer* fgviewerServer = nullptr; } debug; struct { diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 4347e1aa28f8..d67fc1123355 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -1103,8 +1103,13 @@ void FMaterial::precacheDepthVariants(FEngine const& engine) { // later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more // memory and increases init time, but reduces hiccups during the first frame. if (UTILS_UNLIKELY(mIsDefaultMaterial)) { + const bool stereoSupported = mEngine.getDriverApi().isStereoSupported(); auto const allDepthVariants = VariantUtils::getDepthVariants(); for (auto const variant: allDepthVariants) { + // Don't precache any stereo variants if stereo is not supported. + if (!stereoSupported && Variant::isStereoVariant(variant)) { + continue; + } assert_invariant(Variant::isValidDepthVariant(variant)); if (hasVariant(variant)) { prepareProgram(variant); diff --git a/filament/src/details/MorphTargetBuffer.cpp b/filament/src/details/MorphTargetBuffer.cpp index c496d58b06e6..b65cd290a343 100644 --- a/filament/src/details/MorphTargetBuffer.cpp +++ b/filament/src/details/MorphTargetBuffer.cpp @@ -66,7 +66,7 @@ MorphTargetBuffer* MorphTargetBuffer::Builder::build(Engine& engine) { // ------------------------------------------------------------------------------------------------ // This value is limited by ES3.0, ES3.0 only guarantees 2048. -// When you change this value, you must change MAX_MORPH_TARGET_BUFFER_WIDTH at getters.vs +// When you change this value, you must change MAX_MORPH_TARGET_BUFFER_WIDTH at surface_getters.vs constexpr size_t MAX_MORPH_TARGET_BUFFER_WIDTH = 2048; static inline size_t getWidth(size_t const vertexCount) noexcept { diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 768d16b28f78..e9963a17a387 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -781,7 +781,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { cameraInfo.projection = highPrecisionMultiply(ts, cameraInfo.projection); // VERTEX_DOMAIN_DEVICE doesn't apply the projection, but it still needs this - // clip transform, so we apply it separately (see main.vs) + // clip transform, so we apply it separately (see surface_main.vs) cameraInfo.clipTransform = { ts[0][0], ts[1][1], ts[3].x, ts[3].y }; // adjust svp to the new, larger, rendering dimensions @@ -1443,6 +1443,13 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { fg.compile(); +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + fgviewerServer->update(view.getViewHandle(), fg.getFrameGraphInfo(view.getName())); + } +#endif + //fg.export_graphviz(slog.d, view.getName()); fg.execute(driver); diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 8386aab0b618..1b608a3aff58 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -174,7 +174,7 @@ void FSkinningBuffer::setBones(FEngine& engine, Handle handle, } // This value is limited by ES3.0, ES3.0 only guarantees 2048. -// When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at getters.vs +// When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at surface_getters.vs constexpr size_t MAX_SKINNING_BUFFER_WIDTH = 2048; static inline size_t getSkinningBufferWidth(size_t const pairCount) noexcept { diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index ee1c3d343295..4d2675dace7e 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -469,6 +469,26 @@ void FTexture::setImage(FEngine& engine, size_t const level, const_cast(this)->updateLodRange(level); } +void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept { + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + + // The call to setupExternalImage2 is synchronous, and allows the driver to take ownership of the + // external image on this thread, if necessary. + auto& api = engine.getDriverApi(); + api.setupExternalImage2(image); + + auto texture = api.createTextureExternalImage2(mTarget, mFormat, mWidth, mHeight, mUsage, image); + + if (mTextureIsSwizzled) { + auto const& s = mSwizzle; + auto swizzleView = api.createTextureViewSwizzle(texture, s[0], s[1], s[2], s[3]); + api.destroyTexture(texture); + texture = swizzleView; + } + + setHandles(texture); +} + void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; diff --git a/filament/src/details/Texture.h b/filament/src/details/Texture.h index f4354f2f577c..ad0064b52c47 100644 --- a/filament/src/details/Texture.h +++ b/filament/src/details/Texture.h @@ -66,6 +66,7 @@ class FTexture : public Texture { PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, PrefilterOptions const* options); + void setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept; void setExternalImage(FEngine& engine, void* image) noexcept; void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept; void setExternalStream(FEngine& engine, FStream* stream) noexcept; diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index 3022f4be5963..4aa9b6753202 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -109,6 +109,14 @@ FView::FView(FEngine& engine) } #endif +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + mFrameGraphViewerViewHandle = + fgviewerServer->createView(utils::CString(getName())); + } +#endif + // allocate UBOs mLightUbh = driver.createBufferObject(CONFIG_MAX_LIGHT_COUNT * sizeof(LightsUib), BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC); @@ -153,6 +161,13 @@ void FView::terminate(FEngine& engine) { engine.getDebugRegistry().unregisterDataSource("d.view.frame_info"); } #endif + +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + fgviewerServer->destroyView(mFrameGraphViewerViewHandle); + } +#endif } void FView::setViewport(filament::Viewport const& viewport) noexcept { diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 34c49e40d5ae..054aa8e11c68 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -60,6 +60,14 @@ #include #include +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + using ViewHandle = uint32_t; +} +#endif + #include #include @@ -467,6 +475,10 @@ class FView : public View { return mUniforms; } + fgviewer::ViewHandle getViewHandle() const noexcept { + return mFrameGraphViewerViewHandle; + } + private: struct FPickingQuery : public PickingQuery { private: @@ -600,6 +612,8 @@ class FView : public View { { 0, 0, 0, 1 }, }}; + fgviewer::ViewHandle mFrameGraphViewerViewHandle; + #ifndef NDEBUG struct DebugState { std::unique_ptr> debugFrameHistory{}; diff --git a/filament/src/fg/FrameGraph.cpp b/filament/src/fg/FrameGraph.cpp index 6ccd89576627..55a0cd044c84 100644 --- a/filament/src/fg/FrameGraph.cpp +++ b/filament/src/fg/FrameGraph.cpp @@ -479,6 +479,61 @@ void FrameGraph::export_graphviz(utils::io::ostream& out, char const* name) { mGraph.export_graphviz(out, name); } +fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) const { +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::FrameGraphInfo info{utils::CString(viewName)}; + std::vector passes; + + auto first = mPassNodes.begin(); + const auto activePassNodesEnd = mActivePassNodesEnd; + while (first != activePassNodesEnd) { + PassNode *const pass = *first; + first++; + + assert_invariant(!pass->isCulled()); + std::vector reads; + auto const &readEdges = mGraph.getIncomingEdges(pass); + for (auto const &edge: readEdges) { + // all incoming edges should be valid by construction + assert_invariant(mGraph.isEdgeValid(edge)); + reads.push_back(edge->from); + } + + std::vector writes; + auto const &writeEdges = mGraph.getOutgoingEdges(pass); + for (auto const &edge: writeEdges) { + // It is possible that the node we're writing to has been culled. + // In this case we'd like to ignore the edge. + if (!mGraph.isEdgeValid(edge)) { + continue; + } + writes.push_back(edge->to); + } + passes.emplace_back(utils::CString(pass->getName()), + std::move(reads), std::move(writes)); + } + + std::unordered_map resources; + for (const auto &resource: mResourceNodes) { + std::vector resourceProps; + // TODO: Fill in resource properties + fgviewer::ResourceId id = resource->getId(); + resources.emplace(id, fgviewer::FrameGraphInfo::Resource( + id, utils::CString(resource->getName()), + std::move(resourceProps)) + ); + } + + info.setResources(std::move(resources)); + info.setPasses(std::move(passes)); + + return info; +#else + return fgviewer::FrameGraphInfo(); +#endif +} + + // ------------------------------------------------------------------------------------------------ /* diff --git a/filament/src/fg/FrameGraph.h b/filament/src/fg/FrameGraph.h index 2311e6896786..954e13b79c5f 100644 --- a/filament/src/fg/FrameGraph.h +++ b/filament/src/fg/FrameGraph.h @@ -36,6 +36,14 @@ #include +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + class FrameGraphInfo{}; +} // namespace filament::fgviewer +#endif + namespace filament { class ResourceAllocatorInterface; @@ -434,6 +442,12 @@ class FrameGraph { //! export a graphviz view of the graph void export_graphviz(utils::io::ostream& out, const char* name = nullptr); + /** + * Export a fgviewer::FrameGraphInfo for current graph. + * Note that this function should be called after FrameGraph::compile(). + */ + fgviewer::FrameGraphInfo getFrameGraphInfo(const char *viewName) const; + private: friend class FrameGraphResources; friend class PassNode; diff --git a/filament/src/fsr.cpp b/filament/src/fsr.cpp index 943625355ccc..925db9cd00eb 100644 --- a/filament/src/fsr.cpp +++ b/filament/src/fsr.cpp @@ -26,9 +26,11 @@ namespace filament { using namespace math; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif #define A_CPU 1 #include "materials/fsr/ffx_a.h" @@ -36,7 +38,9 @@ using namespace math; #define FSR_RCAS_F 1 #include "materials/fsr/ffx_fsr1.h" +#if defined(__clang__) #pragma clang diagnostic pop +#endif void FSR_ScalingSetup(FSRUniforms* outUniforms, FSRScalingConfig config) noexcept { // FsrEasu API claims it needs the left-top offset, however that's not true with OpenGL, diff --git a/filament/src/materials/colorGrading/colorGrading.mat b/filament/src/materials/colorGrading/colorGrading.mat index 83712beafe27..20315b5a627e 100644 --- a/filament/src/materials/colorGrading/colorGrading.mat +++ b/filament/src/materials/colorGrading/colorGrading.mat @@ -83,8 +83,8 @@ vertex { fragment { -#include "../../../../shaders/src/dithering.fs" -#include "../../../../shaders/src/vignette.fs" +#include "../../../../shaders/src/inline_dithering.fs" +#include "../../../../shaders/src/inline_vignette.fs" #include "colorGrading.fs" void dummy(){} diff --git a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat index 58459dc2c97b..9c54d8a6bb95 100644 --- a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat +++ b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat @@ -71,8 +71,8 @@ vertex { fragment { -#include "../../../../shaders/src/dithering.fs" -#include "../../../../shaders/src/vignette.fs" +#include "../../../../shaders/src/inline_dithering.fs" +#include "../../../../shaders/src/inline_vignette.fs" #include "colorGrading.fs" void dummy(){} diff --git a/ide/emacs/c-filament-style.el b/ide/emacs/c-filament-style.el index 6b25e52e1b72..e9f58c2d8ec9 100644 --- a/ide/emacs/c-filament-style.el +++ b/ide/emacs/c-filament-style.el @@ -72,7 +72,8 @@ nil if there is none)." (brace-list-intro . c-filament-style-lineup-brace-list-intro) (brace-list-entry . c-filament-style-lineup-brace-list-entry) (brace-list-close . c-filament-style-lineup-brace-list-entry) - (label . [0])))) + (label . [0]) + (member-init-intro . ++)))) (provide 'c-filament-style) diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 9d282311773e..37b823a0092c 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.56.8" + spec.version = "1.57.0" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.8/filament-v1.56.8-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.57.0/filament-v1.57.0-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/libs/fgviewer/include/fgviewer/DebugServer.h b/libs/fgviewer/include/fgviewer/DebugServer.h index d56addf9097f..7a169d4e5d5c 100644 --- a/libs/fgviewer/include/fgviewer/DebugServer.h +++ b/libs/fgviewer/include/fgviewer/DebugServer.h @@ -31,8 +31,6 @@ namespace filament::fgviewer { using ViewHandle = uint32_t; - - /** * Server-side frame graph debugger. * diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index 4092e8a765ec..f5676640fe60 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -28,7 +28,7 @@ namespace filament { // update this when a new version of filament wouldn't work with older materials -static constexpr size_t MATERIAL_VERSION = 56; +static constexpr size_t MATERIAL_VERSION = 57; /** * Supported shading models diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index f21abe129e4b..d03172202776 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -727,7 +727,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { static constexpr size_t MAX_DEPTH_OUTPUT = 1; static_assert(MAX_COLOR_OUTPUT == 8, "When updating MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT, manually update post_process_inputs.fs" - " and post_process.fs"); + " and post_process_main.fs"); // Preview the first shader generated by the given CodeGenParams. // This is used to run Static Code Analysis before generating a package. diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 3a8061e4de50..3d6f3af54278 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -937,15 +937,15 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector& materials, bool overrideMaterial = false); @@ -127,8 +129,9 @@ class MeshAssimp { filament::Material* mDefaultColorMaterial = nullptr; filament::Material* mDefaultTransparentColorMaterial = nullptr; - mutable std::unordered_map mGltfMaterialCache; + std::map mMaterialInstances; + filament::Texture* mDefaultMap = nullptr; filament::Texture* mDefaultNormalMap = nullptr; float mDefaultMetallic = 0.0f; @@ -138,8 +141,6 @@ class MeshAssimp { std::vector mRenderables; std::vector mTextures; - - }; #endif // TNT_FILAMENT_SAMPLE_MESH_ASSIMP_H diff --git a/libs/filamentapp/src/MeshAssimp.cpp b/libs/filamentapp/src/MeshAssimp.cpp index 5e3f403e7567..2027d2fb102f 100644 --- a/libs/filamentapp/src/MeshAssimp.cpp +++ b/libs/filamentapp/src/MeshAssimp.cpp @@ -277,26 +277,25 @@ MeshAssimp::MeshAssimp(Engine& engine) : mEngine(engine) { } MeshAssimp::~MeshAssimp() { + for (Entity renderable : mRenderables) { + mEngine.destroy(renderable); + } mEngine.destroy(mVertexBuffer); mEngine.destroy(mIndexBuffer); + for (auto& item : mMaterialInstances) { + mEngine.destroy(item.second); + } mEngine.destroy(mDefaultColorMaterial); mEngine.destroy(mDefaultTransparentColorMaterial); - mEngine.destroy(mDefaultNormalMap); - mEngine.destroy(mDefaultMap); - for (auto& item : mGltfMaterialCache) { auto material = item.second; mEngine.destroy(material); } - - for (Entity renderable : mRenderables) { - mEngine.destroy(renderable); - } - + mEngine.destroy(mDefaultNormalMap); + mEngine.destroy(mDefaultMap); for (Texture* texture : mTextures) { mEngine.destroy(texture); } - // destroy the Entities itself EntityManager::get().destroy(mRenderables.size(), mRenderables.data()); } @@ -626,6 +625,10 @@ void MeshAssimp::addFromFile(const Path& path, tcm.getInstance(rootEntity) : tcm.getInstance(mRenderables[pindex])); tcm.create(entity, parent, mesh.transform); } + + // Takes over the ownership of the material instances so that resources are gracefully + // destroyed in a correct order. The caller doesn't need to handle the destruction. + mMaterialInstances.swap(materials); } using Assimp::Importer; diff --git a/libs/matdbg/include/matdbg/DebugServer.h b/libs/matdbg/include/matdbg/DebugServer.h index 4340001d6614..86aaa79bd10a 100644 --- a/libs/matdbg/include/matdbg/DebugServer.h +++ b/libs/matdbg/include/matdbg/DebugServer.h @@ -52,7 +52,7 @@ class DebugServer { static std::string_view const kSuccessHeader; static std::string_view const kErrorHeader; - DebugServer(backend::Backend backend, int port); + DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port); ~DebugServer(); /** @@ -97,6 +97,7 @@ class DebugServer { const char* newShaderContent, size_t newShaderLength); const backend::Backend mBackend; + const backend::ShaderLanguage mShaderLanguage; CivetServer* mServer; diff --git a/libs/matdbg/include/matdbg/JsonWriter.h b/libs/matdbg/include/matdbg/JsonWriter.h index 8cfbebd1beea..4291f6f74926 100644 --- a/libs/matdbg/include/matdbg/JsonWriter.h +++ b/libs/matdbg/include/matdbg/JsonWriter.h @@ -46,8 +46,8 @@ class JsonWriter { // The array is of the form [ backend, shaderIndex0, shaderIndex1, ... ] where each // shader index is an active variant. Each bit in the activeVariants bitmask // represents one of the possible variant combinations. - bool writeActiveInfo(const filaflat::ChunkContainer& package, backend::Backend backend, - VariantList activeVariants); + bool writeActiveInfo(const filaflat::ChunkContainer& package, + backend::ShaderLanguage shaderLanguage, VariantList activeVariants); private: utils::CString mJsonString; diff --git a/libs/matdbg/include/matdbg/ShaderReplacer.h b/libs/matdbg/include/matdbg/ShaderReplacer.h index 36b0c536ec7b..ab6f49e33db0 100644 --- a/libs/matdbg/include/matdbg/ShaderReplacer.h +++ b/libs/matdbg/include/matdbg/ShaderReplacer.h @@ -29,11 +29,13 @@ namespace matdbg { // in a manner similar to ShaderExtractor. class ShaderReplacer { public: - ShaderReplacer(backend::Backend backend, const void* data, size_t size); + ShaderReplacer(backend::Backend backend, backend::ShaderLanguage language, + const void* data, size_t size); ~ShaderReplacer(); bool replaceShaderSource(backend::ShaderModel shaderModel, Variant variant, backend::ShaderStage stage, const char* sourceString, size_t stringLength); const uint8_t* getEditedPackage() const; + filamat::ChunkType getMaterialTag() const noexcept; size_t getEditedSize() const; private: bool replaceSpirv(backend::ShaderModel shaderModel, Variant variant, @@ -42,6 +44,7 @@ class ShaderReplacer { filaflat::ChunkContainer mOriginalPackage; filaflat::ChunkContainer* mEditedPackage = nullptr; filamat::ChunkType mMaterialTag = filamat::ChunkType::Unknown; + filamat::ChunkType mDeleteTag = filamat::ChunkType::Unknown; filamat::ChunkType mDictionaryTag = filamat::ChunkType::Unknown; }; diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index c9ef42c0ee0b..d13161eeacbc 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -86,6 +86,8 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, } std::string_view const glsl("glsl"); + std::string_view const essl3("essl3"); + std::string_view const essl1("essl1"); std::string_view const msl("msl"); std::string_view const spirv("spirv"); size_t const qlength = strlen(request->query_string); @@ -109,12 +111,20 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, } if (glindex[0]) { - if (language != glsl) { - return softError("Only GLSL is supported."); + ChunkType chunkType; + ShaderLanguage shaderLanguage; + if (language == essl3) { + chunkType = ChunkType::MaterialGlsl; + shaderLanguage = ShaderLanguage::ESSL3; + } else if (language == essl1) { + chunkType = ChunkType::MaterialEssl1; + shaderLanguage = ShaderLanguage::ESSL1; + } else { + return softError("Only essl3 and essl1 are supported."); } - FixedCapacityVector info(getShaderCount(package, ChunkType::MaterialGlsl)); - if (!getShaderInfo(package, info.data(), ChunkType::MaterialGlsl)) { + FixedCapacityVector info(getShaderCount(package, chunkType)); + if (!getShaderInfo(package, info.data(), chunkType)) { return error(__LINE__, uri); } @@ -123,7 +133,7 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, return error(__LINE__, uri); } - ShaderExtractor extractor(ShaderLanguage::ESSL3, result->package, result->packageSize); + ShaderExtractor extractor(shaderLanguage, result->package, result->packageSize); if (!extractor.parse()) { return error(__LINE__, uri); } @@ -314,7 +324,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return error(__LINE__, uri); } JsonWriter writer; - if (!writer.writeActiveInfo(package, mServer->mBackend, record.activeVariants)) { + if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) { return error(__LINE__, uri); } bool const last = (++index) == mServer->mMaterialRecords.size(); diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index e8efb0b22745..d75952728b8e 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -122,7 +122,8 @@ class FileRequestHandler : public CivetHandler { DebugServer* mServer; }; -DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) { +DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port) + : mBackend(backend), mShaderLanguage(shaderLanguage) { #if !SERVE_FROM_SOURCE_TREE ASSET_MAP["/index.html"] = { @@ -254,47 +255,23 @@ bool DebugServer::handleEditCommand(const MaterialKey& key, backend::Backend api return error(__LINE__); } - FixedCapacityVector infos; - size_t shaderCount; - switch (api) { - case backend::Backend::OPENGL: { - shaderCount = getShaderCount(package, ChunkType::MaterialGlsl); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialGlsl)) { - return error(__LINE__); - } - break; - } - case backend::Backend::VULKAN: { - shaderCount = getShaderCount(package, ChunkType::MaterialSpirv); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialSpirv)) { - return error(__LINE__); - } - break; - } - case backend::Backend::METAL: { - shaderCount = getShaderCount(package, ChunkType::MaterialMetal); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialMetal)) { - return error(__LINE__); - } - break; - } - default: - error(__LINE__); - } + ShaderReplacer editor(api, mShaderLanguage, package.getData(), package.getSize()); + size_t shaderCount = getShaderCount(package, editor.getMaterialTag()); if (shaderIndex < 0 || shaderIndex >= shaderCount) { return error(__LINE__); } + FixedCapacityVector infos; + infos.reserve(shaderCount); + infos.resize(shaderCount); + if (!getShaderInfo(package, infos.data(), editor.getMaterialTag())) { + return error(__LINE__); + } + const ShaderInfo info = infos[shaderIndex]; - ShaderReplacer editor(api, package.getData(), package.getSize()); - if (!editor.replaceShaderSource(info.shaderModel, info.variant, info.pipelineStage, source, size)) { + if (!editor.replaceShaderSource(info.shaderModel, info.variant, info.pipelineStage, source, + size)) { return error(__LINE__); } diff --git a/libs/matdbg/src/JsonWriter.cpp b/libs/matdbg/src/JsonWriter.cpp index c9e94c8143d7..2a22eaeae2e9 100644 --- a/libs/matdbg/src/JsonWriter.cpp +++ b/libs/matdbg/src/JsonWriter.cpp @@ -136,13 +136,22 @@ static void printShaderInfo(ostream& json, const vector& info, const } } -static bool printGlslInfo(ostream& json, const ChunkContainer& container) { +static bool printGlslInfo(ostream& json, const ChunkContainer& container, ChunkType chunkType) { std::vector info; - info.resize(getShaderCount(container, ChunkType::MaterialGlsl)); - if (!getShaderInfo(container, info.data(), ChunkType::MaterialGlsl)) { + info.resize(getShaderCount(container, chunkType)); + if (!getShaderInfo(container, info.data(), chunkType)) { return false; } - json << "\"opengl\": [\n"; + switch (chunkType) { + case ChunkType::MaterialEssl1: + json << "\"essl1\": [\n"; + break; + case ChunkType::MaterialGlsl: + json << "\"opengl\": [\n"; + break; + default: + assert(false); // unreachable + } printShaderInfo(json, info, container); json << "],\n"; return true; @@ -180,7 +189,10 @@ bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) { if (!printParametersInfo(json, container)) { return false; } - if (!printGlslInfo(json, container)) { + if (!printGlslInfo(json, container, ChunkType::MaterialGlsl)) { + return false; + } + if (!printGlslInfo(json, container, ChunkType::MaterialEssl1)) { return false; } if (!printVkInfo(json, container)) { @@ -220,29 +232,34 @@ size_t JsonWriter::getJsonSize() const { } bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, - Backend backend, VariantList activeVariants) { + ShaderLanguage shaderLanguage, VariantList activeVariants) { vector shaders; ostringstream json; json << "[\""; - switch (backend) { - case Backend::OPENGL: - shaders.resize(getShaderCount(package, ChunkType::MaterialGlsl)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialGlsl); + ChunkType chunkType; + switch (shaderLanguage) { + case ShaderLanguage::ESSL1: + json << "essl1"; + chunkType = ChunkType::MaterialEssl1; + break; + case ShaderLanguage::ESSL3: json << "opengl"; + chunkType = ChunkType::MaterialGlsl; break; - case Backend::VULKAN: - shaders.resize(getShaderCount(package, ChunkType::MaterialSpirv)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialSpirv); + case ShaderLanguage::SPIRV: json << "vulkan"; + chunkType = ChunkType::MaterialSpirv; break; - case Backend::METAL: - shaders.resize(getShaderCount(package, ChunkType::MaterialMetal)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialMetal); + case ShaderLanguage::MSL: json << "metal"; + chunkType = ChunkType::MaterialMetal; break; default: return false; } + shaders.resize(getShaderCount(package, chunkType)); + getShaderInfo(package, shaders.data(), chunkType); + json << "\""; for (size_t variant = 0; variant < activeVariants.size(); variant++) { if (activeVariants[variant]) { diff --git a/libs/matdbg/src/ShaderReplacer.cpp b/libs/matdbg/src/ShaderReplacer.cpp index 8a457e598c98..38e4b5822962 100644 --- a/libs/matdbg/src/ShaderReplacer.cpp +++ b/libs/matdbg/src/ShaderReplacer.cpp @@ -94,22 +94,33 @@ class BlobIndex { filaflat::BlobDictionary mDataBlobs; }; -ShaderReplacer::ShaderReplacer(Backend backend, const void* data, size_t size) : +ShaderReplacer::ShaderReplacer(Backend backend, ShaderLanguage language, + const void* data, size_t size) : mBackend(backend), mOriginalPackage(data, size) { - switch (backend) { - case Backend::OPENGL: + switch (language) { + // ESSL1 and ESSL3 share the same dictionary, and replacing either will corrupt the other. + // If replacing one, delete both. + case backend::ShaderLanguage::ESSL1: + mMaterialTag = ChunkType::MaterialEssl1; + mDeleteTag = ChunkType::MaterialGlsl; + mDictionaryTag = ChunkType::DictionaryText; + break; + case backend::ShaderLanguage::ESSL3: mMaterialTag = ChunkType::MaterialGlsl; + mDeleteTag = ChunkType::MaterialEssl1; mDictionaryTag = ChunkType::DictionaryText; break; - case Backend::METAL: + case backend::ShaderLanguage::MSL: mMaterialTag = ChunkType::MaterialMetal; mDictionaryTag = ChunkType::DictionaryText; break; - case Backend::VULKAN: + case backend::ShaderLanguage::SPIRV: mMaterialTag = ChunkType::MaterialSpirv; mDictionaryTag = ChunkType::DictionarySpirv; break; - default: + case backend::ShaderLanguage::METAL_LIBRARY: + mMaterialTag = ChunkType::MaterialMetalLibrary; + mDictionaryTag = ChunkType::DictionaryMetalLibrary; break; } } @@ -133,7 +144,7 @@ bool ShaderReplacer::replaceShaderSource(ShaderModel shaderModel, Variant varian return replaceSpirv(shaderModel, variant, stage, sourceString, stringLength); } - // Clone all chunks except Dictionary* and Material*. + // Clone (almost) all chunks except Dictionary* and Material*. stringstream sstream(std::string((const char*) cc.getData(), cc.getSize())); stringstream tstream; { @@ -145,7 +156,9 @@ bool ShaderReplacer::replaceShaderSource(ShaderModel shaderModel, Variant varian sstream.read((char*) &size, sizeof(size)); content.resize(size); sstream.read((char*) content.data(), size); - if (ChunkType(type) == mDictionaryTag|| ChunkType(type) == mMaterialTag) { + if (ChunkType(type) == mDictionaryTag + || ChunkType(type) == mDeleteTag + || ChunkType(type) == mMaterialTag) { continue; } tstream.write((char*) &type, sizeof(type)); @@ -297,6 +310,10 @@ size_t ShaderReplacer::getEditedSize() const { return mEditedPackage->getSize(); } +filamat::ChunkType ShaderReplacer::getMaterialTag() const noexcept { + return mMaterialTag; +} + ShaderIndex::ShaderIndex(ChunkType dictTag, ChunkType matTag, const filaflat::ChunkContainer& cc) : mDictTag(dictTag), mMatTag(matTag) { diff --git a/libs/matdbg/web/api.js b/libs/matdbg/web/api.js index 3a580fcacfe4..f16fec3a90ea 100644 --- a/libs/matdbg/web/api.js +++ b/libs/matdbg/web/api.js @@ -30,6 +30,7 @@ async function fetchShaderCode(matid, backend, language, index) { let query; switch (backend) { case "opengl": + case "essl1": query = `type=${language}&glindex=${index}`; break; case "vulkan": @@ -82,7 +83,10 @@ async function queryActiveShaders() { function rebuildMaterial(materialId, backend, shaderIndex, editedText) { let api = 0; switch (backend) { - case "opengl": api = 1; break; + case "opengl": + case "essl1": + api = 1; + break; case "vulkan": api = 2; break; case "metal": api = 3; break; } diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index 325d47487fd6..58858daa3c9c 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -20,11 +20,19 @@ const kUntitledPlaceholder = "untitled"; // Maps to backend to the languages allowed for that backend. const LANGUAGE_CHOICES = { - 'opengl': ['glsl'], + 'opengl': ['essl3', 'essl1'], + 'essl1': ['essl3', 'essl1'], 'vulkan': ['glsl', 'spirv'], 'metal': ['msl'], }; +const DEFAULT_LANGUAGE_FOR_BACKEND = { + 'opengl': 'essl3', + 'essl1': 'essl1', + 'vulkan': 'glsl', + 'metal': 'msl', +}; + const BACKENDS = Object.keys(LANGUAGE_CHOICES); const MATERIAL_INFO_KEY_TO_STRING = { @@ -1051,9 +1059,8 @@ class MatdbgViewer extends LitElement { updated(props) { // Set a language if there hasn't been one set. if (props.has('currentBackend') && this.currentBackend) { - const choices = LANGUAGE_CHOICES[this.currentBackend]; - if (choices.indexOf(this.currentLanguage) < 0) { - this.currentLanguage = choices[0]; + if (LANGUAGE_CHOICES[this.currentBackend].indexOf(this.currentLanguage) < 0) { + this.currentLanguage = DEFAULT_LANGUAGE_FOR_BACKEND[this.currentBackend]; } } if (props.has('currentMaterial')) { diff --git a/samples/hellopbr.cpp b/samples/hellopbr.cpp index f5cae37706e1..c1163c8854c1 100644 --- a/samples/hellopbr.cpp +++ b/samples/hellopbr.cpp @@ -146,8 +146,8 @@ int main(int argc, char** argv) { auto cleanup = [&app](Engine* engine, View*, Scene*) { engine->destroy(app.light); - engine->destroy(app.materialInstance); engine->destroy(app.mesh.renderable); + engine->destroy(app.materialInstance); engine->destroy(app.material); }; diff --git a/samples/hellostereo.cpp b/samples/hellostereo.cpp index 06936241a850..41c5c4a198cf 100644 --- a/samples/hellostereo.cpp +++ b/samples/hellostereo.cpp @@ -218,7 +218,7 @@ int main(int argc, char** argv) { .depth(eyeCount) .levels(1) .sampler(Texture::Sampler::SAMPLER_2D_ARRAY) - .format(Texture::InternalFormat::DEPTH24) + .format(Texture::InternalFormat::DEPTH32F) .usage(Texture::Usage::DEPTH_ATTACHMENT) .build(*engine); app.stereoRenderTarget = RenderTarget::Builder() @@ -324,12 +324,12 @@ int main(int argc, char** argv) { auto& em = utils::EntityManager::get(); - for (MaterialInstance* mi : app.quadMatInstances) { - engine->destroy(mi); - } for (utils::Entity e : app.quadEntities) { engine->destroy(e); } + for (MaterialInstance* mi : app.quadMatInstances) { + engine->destroy(mi); + } engine->destroy(app.quadMaterial); engine->destroy(app.quadIb); engine->destroy(app.quadVb); diff --git a/samples/rendertarget.cpp b/samples/rendertarget.cpp index 9ff53ccc37d2..4e7860d72675 100644 --- a/samples/rendertarget.cpp +++ b/samples/rendertarget.cpp @@ -209,7 +209,7 @@ int main(int argc, char** argv) { app.offscreenDepthTexture = Texture::Builder() .width(vp.width).height(vp.height).levels(1) .usage(Texture::Usage::DEPTH_ATTACHMENT) - .format(Texture::InternalFormat::DEPTH24).build(*engine); + .format(Texture::InternalFormat::DEPTH32F).build(*engine); app.offscreenRenderTarget = RenderTarget::Builder() .texture(RenderTarget::AttachmentPoint::COLOR, app.offscreenColorTexture) .texture(RenderTarget::AttachmentPoint::DEPTH, app.offscreenDepthTexture) @@ -321,11 +321,11 @@ int main(int argc, char** argv) { engine->destroy(app.reflectedMonkey); engine->destroy(app.lightEntity); engine->destroy(app.quadEntity); - engine->destroy(app.meshMatInstance); - engine->destroy(app.meshMaterial); engine->destroy(app.monkeyMesh.renderable); engine->destroy(app.monkeyMesh.vertexBuffer); engine->destroy(app.monkeyMesh.indexBuffer); + engine->destroy(app.meshMatInstance); + engine->destroy(app.meshMaterial); engine->destroy(app.offscreenColorTexture); engine->destroy(app.offscreenDepthTexture); engine->destroy(app.offscreenRenderTarget); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index a2da0b1b5b5d..d00e9413eb46 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -639,6 +639,15 @@ int main(int argc, char** argv) { }; auto cleanup = [&app](Engine* engine, View*, Scene*) { + for (auto i = 0; i < 4; i++) { + engine->destroy(app.renderables[i]); + } + for (auto i = 0; i < app.boCount; i++) { + engine->destroy(app.bos[i]); + } + for (auto i = 0; i < app.vbCount; i++) { + engine->destroy(app.vbs[i]); + } engine->destroy(app.skybox); engine->destroy(app.mat); engine->destroy(app.ib); @@ -648,15 +657,6 @@ int main(int argc, char** argv) { engine->destroy(app.mt); engine->destroyCameraComponent(app.camera); EntityManager::get().destroy(app.camera); - for (auto i = 0; i < app.vbCount; i++) { - engine->destroy(app.vbs[i]); - } - for ( auto i = 0; i < app.boCount; i++) { - engine->destroy(app.bos[i]); - } - for ( auto i = 0; i < 4; i++) { - engine->destroy(app.renderables[i]); - } }; FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { diff --git a/samples/suzanne.cpp b/samples/suzanne.cpp index dae42d353ee5..8eeeef8ef0d7 100644 --- a/samples/suzanne.cpp +++ b/samples/suzanne.cpp @@ -199,8 +199,8 @@ int main(int argc, char** argv) { }; auto cleanup = [&app](Engine* engine, View*, Scene*) { - engine->destroy(app.materialInstance); engine->destroy(app.mesh.renderable); + engine->destroy(app.materialInstance); engine->destroy(app.material); engine->destroy(app.albedo); engine->destroy(app.normal); diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index dbabd77ab389..7109c239c2f6 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -11,48 +11,48 @@ endif() # Sources and headers # ================================================================================================== set(SHADERS - src/ambient_occlusion.fs - src/brdf.fs + src/surface_ambient_occlusion.fs + src/surface_brdf.fs src/common_defines.glsl src/common_getters.glsl - src/common_instancing.glsl + src/surface_instancing.glsl src/common_graphics.fs - src/common_lighting.fs - src/common_material.fs + src/surface_lighting.fs + src/surface_material.fs src/common_math.glsl src/common_shading.fs - src/common_shadowing.glsl - src/common_types.glsl - src/depth_main.fs - src/fog.fs - src/getters.cs - src/getters.fs - src/getters.vs - src/light_directional.fs - src/light_indirect.fs - src/light_reflections.fs - src/light_punctual.fs - src/main.cs - src/main.fs - src/main.vs - src/material_inputs.fs - src/material_inputs.vs - src/post_process.fs - src/post_process.vs + src/surface_shadowing.glsl + src/surface_types.glsl + src/surface_depth_main.fs + src/surface_fog.fs + src/surface_getters.cs + src/surface_getters.fs + src/surface_getters.vs + src/surface_light_directional.fs + src/surface_light_indirect.fs + src/surface_light_reflections.fs + src/surface_light_punctual.fs + src/surface_main.cs + src/surface_main.fs + src/surface_main.vs + src/surface_material_inputs.fs + src/surface_material_inputs.vs + src/post_process_main.fs + src/post_process_main.vs src/post_process_getters.vs src/post_process_inputs.fs src/post_process_inputs.vs - src/shading_lit.fs - src/shading_lit_custom.fs - src/shading_model_cloth.fs - src/shading_model_standard.fs - src/shading_model_subsurface.fs - src/shading_parameters.fs - src/shading_reflections.fs - src/shading_unlit.fs - src/shadowing.fs - src/varyings.glsl - src/vignette.fs + src/surface_shading_lit.fs + src/surface_shading_lit_custom.fs + src/surface_shading_model_cloth.fs + src/surface_shading_model_standard.fs + src/surface_shading_model_subsurface.fs + src/surface_shading_parameters.fs + src/surface_shading_reflections.fs + src/surface_shading_unlit.fs + src/surface_shadowing.fs + src/surface_varyings.glsl + src/inline_vignette.fs ) # These files aren't part of libshaders, but are included by materials inside @@ -60,7 +60,7 @@ set(SHADERS # # tone_mapping.fs # conversion_functions.fs -# dithering.fs +# inline_dithering.fs set(MINIFIED_DIR ${CMAKE_CURRENT_BINARY_DIR}/minified) diff --git a/shaders/src/README.md b/shaders/src/README.md new file mode 100644 index 000000000000..ccc73bf5aaca --- /dev/null +++ b/shaders/src/README.md @@ -0,0 +1,34 @@ +# Shader Code Directory + +This directory contains GLSL (OpenGL Shading Language) code snippets, organized by their function and stage in the graphics pipeline. These snippets are designed to be used as **building blocks** by the **Shader Generator** within this project. Instead of being compiled directly, these snippets are combined and processed to generate complete, functional shader programs for various purposes. + + +## File Naming Convention + +Shader files within this directory follow a consistent naming convention to easily identify their purpose and usage: + +`prefix_name.suffix` + +### Prefixes + +The prefix indicates the domain or category of the shader code: + +* **`surface`:** Snippets with this prefix are intended for use in **surface shaders**. Surface shaders define the visual properties of object surfaces, handling aspects like lighting, texturing, and material properties. +* **`post_process`:** Snippets with this prefix are used in **post-processing shaders**. Post-processing shaders operate on the entire rendered image after the main rendering pass to achieve effects such as blur, bloom, color correction, and more. +* **`common`:** Snippets with this prefix contain **shared code** that can be used by **both** `surface` and `post_process` shaders. This includes utility functions, common data structures, and reusable logic, promoting modularity and reducing code duplication. +* **`inline`:** Snippets with this prefix are **specifically designed to be directly included within other shader files** during the generation process. They often contain reusable functions or macros that need to be present in the final shader code but not necessarily categorized as `surface` or `post_process`. + +### Suffixes (Extensions) + +The suffix (file extension) specifies the **shader stage** that the code snippet is intended for: + +* **`.vs`:** Files with this extension contain code snippets for **vertex shaders**. Vertex shaders operate on individual vertices and are typically used to transform vertex positions, calculate normals, and pass data to the fragment shader. +* **`.fs`:** Files with this extension contain code snippets for **fragment shaders**. Fragment shaders, also known as pixel shaders, determine the final color of each pixel. They are used for lighting, texturing, and other per-pixel operations. +* **`.cs`:** Files with this extension contain code snippets for **compute shaders**. Compute shaders are used for general-purpose computation on the GPU, outside the traditional rendering pipeline. They can be used for tasks like physics simulations, image processing, and more. (Currently not implemented yet) +* **`.glsl`:** Files with this extension contain **reusable GLSL code snippets, including functions, structures, or constants**, that are intended to be included or linked into multiple shader stages (vertex, fragment, or compute). This is a generic extension to signify that the file does not belong exclusively to a single shader stage. + +## Example + +* `surface_light_directional.fs`: Fragment shader snippets for objects using the directional lighting model. +* `post_process_getters.vs`: Vertex shader snippets containing reusable getter functions for post-processing shaders. +* `common_math.glsl`: GLSL code with reusable math constants and functions shared by both surface and post-processing shaders. diff --git a/shaders/src/common_getters.glsl b/shaders/src/common_getters.glsl index 23a365549afe..95ea0799f214 100644 --- a/shaders/src/common_getters.glsl +++ b/shaders/src/common_getters.glsl @@ -28,7 +28,13 @@ highp mat4 getClipFromWorldMatrix() { int eye = instance_index % CONFIG_STEREO_EYE_COUNT; return frameUniforms.clipFromWorldMatrix[eye]; #elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) + +#if defined(TARGET_VULKAN_ENVIRONMENT) + return frameUniforms.clipFromWorldMatrix[gl_ViewIndex]; +#else return frameUniforms.clipFromWorldMatrix[gl_ViewID_OVR]; +#endif // TARGET_VULKAN_ENVIRONMENT + #else return frameUniforms.clipFromWorldMatrix[0]; #endif diff --git a/shaders/src/dithering.fs b/shaders/src/inline_dithering.fs similarity index 100% rename from shaders/src/dithering.fs rename to shaders/src/inline_dithering.fs diff --git a/shaders/src/vignette.fs b/shaders/src/inline_vignette.fs similarity index 100% rename from shaders/src/vignette.fs rename to shaders/src/inline_vignette.fs diff --git a/shaders/src/post_process.fs b/shaders/src/post_process_main.fs similarity index 100% rename from shaders/src/post_process.fs rename to shaders/src/post_process_main.fs diff --git a/shaders/src/post_process.vs b/shaders/src/post_process_main.vs similarity index 100% rename from shaders/src/post_process.vs rename to shaders/src/post_process_main.vs diff --git a/shaders/src/ambient_occlusion.fs b/shaders/src/surface_ambient_occlusion.fs similarity index 100% rename from shaders/src/ambient_occlusion.fs rename to shaders/src/surface_ambient_occlusion.fs diff --git a/shaders/src/brdf.fs b/shaders/src/surface_brdf.fs similarity index 100% rename from shaders/src/brdf.fs rename to shaders/src/surface_brdf.fs diff --git a/shaders/src/depth_main.fs b/shaders/src/surface_depth_main.fs similarity index 97% rename from shaders/src/depth_main.fs rename to shaders/src/surface_depth_main.fs index e50d7620f171..63a07ce068bd 100644 --- a/shaders/src/depth_main.fs +++ b/shaders/src/surface_depth_main.fs @@ -40,7 +40,7 @@ void main() { #endif #if defined(MATERIAL_HAS_TRANSPARENT_SHADOW) - // Interleaved gradient noise, see dithering.fs + // Interleaved gradient noise, see inline_dithering.fs float noise = interleavedGradientNoise(gl_FragCoord.xy); if (noise >= alpha) { discard; @@ -49,7 +49,7 @@ void main() { #endif #if defined(VARIANT_HAS_VSM) - // interpolated depth is stored in vertex_worldPosition.w (see main.vs) + // interpolated depth is stored in vertex_worldPosition.w (see surface_main.vs) // we always compute the "negative" side of ELVSM because the cost is small, and this allows // EVSM/ELVSM choice to be done on the CPU side more easily. highp float depth = vertex_worldPosition.w; diff --git a/shaders/src/fog.fs b/shaders/src/surface_fog.fs similarity index 100% rename from shaders/src/fog.fs rename to shaders/src/surface_fog.fs diff --git a/shaders/src/getters.cs b/shaders/src/surface_getters.cs similarity index 100% rename from shaders/src/getters.cs rename to shaders/src/surface_getters.cs diff --git a/shaders/src/getters.fs b/shaders/src/surface_getters.fs similarity index 100% rename from shaders/src/getters.fs rename to shaders/src/surface_getters.fs diff --git a/shaders/src/getters.vs b/shaders/src/surface_getters.vs similarity index 98% rename from shaders/src/getters.vs rename to shaders/src/surface_getters.vs index 09569c61554e..a9b8c293ac2b 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/surface_getters.vs @@ -284,8 +284,14 @@ int getEyeIndex() { #if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED) return instance_index % CONFIG_STEREO_EYE_COUNT; #elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) + +#if defined(TARGET_VULKAN_ENVIRONMENT) + return int(gl_ViewIndex); +#else // gl_ViewID_OVR is of uint type, which needs an explicit conversion. return int(gl_ViewID_OVR); +#endif // TARGET_VULKAN_ENVIRONMENT + #endif return 0; } diff --git a/shaders/src/common_instancing.glsl b/shaders/src/surface_instancing.glsl similarity index 100% rename from shaders/src/common_instancing.glsl rename to shaders/src/surface_instancing.glsl diff --git a/shaders/src/light_directional.fs b/shaders/src/surface_light_directional.fs similarity index 100% rename from shaders/src/light_directional.fs rename to shaders/src/surface_light_directional.fs diff --git a/shaders/src/light_indirect.fs b/shaders/src/surface_light_indirect.fs similarity index 100% rename from shaders/src/light_indirect.fs rename to shaders/src/surface_light_indirect.fs diff --git a/shaders/src/light_punctual.fs b/shaders/src/surface_light_punctual.fs similarity index 99% rename from shaders/src/light_punctual.fs rename to shaders/src/surface_light_punctual.fs index fa55b0572815..a4d1f9125754 100644 --- a/shaders/src/light_punctual.fs +++ b/shaders/src/surface_light_punctual.fs @@ -115,7 +115,7 @@ float getAngleAttenuation(const highp vec3 lightDir, const highp vec3 l, const h } /** - * Returns a Light structure (see common_lighting.fs) describing a point or spot light. + * Returns a Light structure (see surface_lighting.fs) describing a point or spot light. * The colorIntensity field will store the *pre-exposed* intensity of the light * in the w component. * diff --git a/shaders/src/light_reflections.fs b/shaders/src/surface_light_reflections.fs similarity index 100% rename from shaders/src/light_reflections.fs rename to shaders/src/surface_light_reflections.fs diff --git a/shaders/src/common_lighting.fs b/shaders/src/surface_lighting.fs similarity index 100% rename from shaders/src/common_lighting.fs rename to shaders/src/surface_lighting.fs diff --git a/shaders/src/main.cs b/shaders/src/surface_main.cs similarity index 100% rename from shaders/src/main.cs rename to shaders/src/surface_main.cs diff --git a/shaders/src/main.fs b/shaders/src/surface_main.fs similarity index 96% rename from shaders/src/main.fs rename to shaders/src/surface_main.fs index c0d6bdb61f86..c9383a7bb0b9 100644 --- a/shaders/src/main.fs +++ b/shaders/src/surface_main.fs @@ -43,11 +43,11 @@ void main() { initObjectUniforms(); - // See shading_parameters.fs + // See surface_shading_parameters.fs // Computes global variables we need to evaluate material and lighting computeShadingParams(); - // Initialize the inputs to sensible default values, see material_inputs.fs + // Initialize the inputs to sensible default values, see surface_material_inputs.fs MaterialInputs inputs; initMaterial(inputs); diff --git a/shaders/src/main.vs b/shaders/src/surface_main.vs similarity index 99% rename from shaders/src/main.vs rename to shaders/src/surface_main.vs index bbb9230fc8d8..c8882de005cf 100644 --- a/shaders/src/main.vs +++ b/shaders/src/surface_main.vs @@ -33,7 +33,7 @@ void main() { initObjectUniforms(); - // Initialize the inputs to sensible default values, see material_inputs.vs + // Initialize the inputs to sensible default values, see surface_material_inputs.vs #if defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER) // In USE_OPTIMIZED_DEPTH_VERTEX_SHADER mode, we can even skip this if we're already in diff --git a/shaders/src/common_material.fs b/shaders/src/surface_material.fs similarity index 100% rename from shaders/src/common_material.fs rename to shaders/src/surface_material.fs diff --git a/shaders/src/material_inputs.fs b/shaders/src/surface_material_inputs.fs similarity index 100% rename from shaders/src/material_inputs.fs rename to shaders/src/surface_material_inputs.fs diff --git a/shaders/src/material_inputs.vs b/shaders/src/surface_material_inputs.vs similarity index 100% rename from shaders/src/material_inputs.vs rename to shaders/src/surface_material_inputs.vs diff --git a/shaders/src/shading_lit.fs b/shaders/src/surface_shading_lit.fs similarity index 100% rename from shaders/src/shading_lit.fs rename to shaders/src/surface_shading_lit.fs diff --git a/shaders/src/shading_lit_custom.fs b/shaders/src/surface_shading_lit_custom.fs similarity index 100% rename from shaders/src/shading_lit_custom.fs rename to shaders/src/surface_shading_lit_custom.fs diff --git a/shaders/src/shading_model_cloth.fs b/shaders/src/surface_shading_model_cloth.fs similarity index 100% rename from shaders/src/shading_model_cloth.fs rename to shaders/src/surface_shading_model_cloth.fs diff --git a/shaders/src/shading_model_standard.fs b/shaders/src/surface_shading_model_standard.fs similarity index 97% rename from shaders/src/shading_model_standard.fs rename to shaders/src/surface_shading_model_standard.fs index ca71d1de0fef..0931fda63d88 100644 --- a/shaders/src/shading_model_standard.fs +++ b/shaders/src/surface_shading_model_standard.fs @@ -91,7 +91,7 @@ vec3 diffuseLobe(const PixelParams pixel, float NoV, float NoL, float LoH) { * Surface BRDF * The surface BRDF uses a diffuse lobe and a specular lobe to render both * dielectrics and conductors. The specular lobe is based on the Cook-Torrance - * micro-facet model (see brdf.fs for more details). In addition, the specular + * micro-facet model (see surface_brdf.fs for more details). In addition, the specular * can be either isotropic or anisotropic. * * Clear coat BRDF @@ -99,7 +99,7 @@ vec3 diffuseLobe(const PixelParams pixel, float NoV, float NoL, float LoH) { * top of the surface. Its IOR is set to 1.5 (polyutherane) to simplify * our computations. This BRDF only contains a specular lobe and while based * on the Cook-Torrance microfacet model, it uses cheaper terms than the surface - * BRDF's specular lobe (see brdf.fs). + * BRDF's specular lobe (see surface_brdf.fs). */ vec3 surfaceShading(const PixelParams pixel, const Light light, float occlusion) { vec3 h = normalize(shading_view + light.l); diff --git a/shaders/src/shading_model_subsurface.fs b/shaders/src/surface_shading_model_subsurface.fs similarity index 95% rename from shaders/src/shading_model_subsurface.fs rename to shaders/src/surface_shading_model_subsurface.fs index c29c62a4102b..d608edafa375 100644 --- a/shaders/src/shading_model_subsurface.fs +++ b/shaders/src/surface_shading_model_subsurface.fs @@ -1,6 +1,6 @@ /** * Evalutes lit materials with the subsurface shading model. This model is a - * combination of a BRDF (the same used in shading_model_standard.fs, refer to that + * combination of a BRDF (the same used in surface_shading_model_standard.fs, refer to that * file for more information) and of an approximated BTDF to simulate subsurface * scattering. The BTDF itself is not physically based and does not represent a * correct interpretation of transmission events. diff --git a/shaders/src/shading_parameters.fs b/shaders/src/surface_shading_parameters.fs similarity index 100% rename from shaders/src/shading_parameters.fs rename to shaders/src/surface_shading_parameters.fs diff --git a/shaders/src/shading_reflections.fs b/shaders/src/surface_shading_reflections.fs similarity index 100% rename from shaders/src/shading_reflections.fs rename to shaders/src/surface_shading_reflections.fs diff --git a/shaders/src/shading_unlit.fs b/shaders/src/surface_shading_unlit.fs similarity index 100% rename from shaders/src/shading_unlit.fs rename to shaders/src/surface_shading_unlit.fs diff --git a/shaders/src/shadowing.fs b/shaders/src/surface_shadowing.fs similarity index 100% rename from shaders/src/shadowing.fs rename to shaders/src/surface_shadowing.fs diff --git a/shaders/src/common_shadowing.glsl b/shaders/src/surface_shadowing.glsl similarity index 100% rename from shaders/src/common_shadowing.glsl rename to shaders/src/surface_shadowing.glsl diff --git a/shaders/src/common_types.glsl b/shaders/src/surface_types.glsl similarity index 100% rename from shaders/src/common_types.glsl rename to shaders/src/surface_types.glsl diff --git a/shaders/src/varyings.glsl b/shaders/src/surface_varyings.glsl similarity index 97% rename from shaders/src/varyings.glsl rename to shaders/src/surface_varyings.glsl index a0478838ded4..7c1432ef989b 100644 --- a/shaders/src/varyings.glsl +++ b/shaders/src/surface_varyings.glsl @@ -32,7 +32,7 @@ LAYOUT_LOCATION(10) VARYING highp vec4 vertex_uv01; LAYOUT_LOCATION(11) VARYING highp vec4 vertex_lightSpacePosition; #endif -// Note that fragColor is an output and is not declared here; see main.fs and depth_main.fs +// Note that fragColor is an output and is not declared here; see surface_main.fs and surface_depth_main.fs #if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED) #if defined(GL_ES) && defined(FILAMENT_GLSLANG) diff --git a/third_party/abseil/tnt/CMakeLists.txt b/third_party/abseil/tnt/CMakeLists.txt new file mode 100644 index 000000000000..8481d7ad3ffd --- /dev/null +++ b/third_party/abseil/tnt/CMakeLists.txt @@ -0,0 +1,109 @@ +add_subdirectory(../ "${CMAKE_CURRENT_BINARY_DIR}/abseil") + +# To make Abseil easy for clients to link against, we create a dummy target just for installation +# purposes and combine all of Abseil's libraries into a single, easy to link against static library. +add_library(filament-abseil STATIC dummy.c) + +set(ABSEIL_DEPS + # This is a full list of static library targets that Abseil exports, generated with the + # following commands: + # cd out/cmake-debug + # ninja -t targets | grep libabsl | sed 's/^lib//; s/\.a: phony$//' + absl_bad_any_cast_impl + absl_bad_optional_access + absl_bad_variant_access + absl_base + absl_city + absl_civil_time + absl_cord + absl_cord_internal + absl_cordz_functions + absl_cordz_handle + absl_cordz_info + absl_cordz_sample_token + absl_crc32c + absl_crc_cord_state + absl_crc_cpu_detect + absl_crc_internal + absl_debugging_internal + absl_decode_rust_punycode + absl_demangle_internal + absl_demangle_rust + absl_die_if_null + absl_examine_stack + absl_exponential_biased + absl_failure_signal_handler + absl_flags_commandlineflag + absl_flags_commandlineflag_internal + absl_flags_config + absl_flags_internal + absl_flags_marshalling + absl_flags_parse + absl_flags_private_handle_accessor + absl_flags_program_name + absl_flags_reflection + absl_flags_usage + absl_flags_usage_internal + absl_graphcycles_internal + absl_hash + absl_hashtablez_sampler + absl_int128 + absl_kernel_timeout_internal + absl_leak_check + absl_log_entry + absl_log_flags + absl_log_globals + absl_log_initialize + absl_log_internal_check_op + absl_log_internal_conditions + absl_log_internal_fnmatch + absl_log_internal_format + absl_log_internal_globals + absl_log_internal_log_sink_set + absl_log_internal_message + absl_log_internal_nullguard + absl_log_internal_proto + absl_log_internal_structured_proto + absl_log_severity + absl_log_sink + absl_low_level_hash + absl_malloc_internal + absl_periodic_sampler + absl_poison + absl_random_distributions + absl_random_internal_distribution_test_util + absl_random_internal_platform + absl_random_internal_pool_urbg + absl_random_internal_randen + absl_random_internal_randen_hwaes + absl_random_internal_randen_hwaes_impl + absl_random_internal_randen_slow + absl_random_internal_seed_material + absl_random_seed_gen_exception + absl_random_seed_sequences + absl_raw_hash_set + absl_raw_logging_internal + absl_scoped_set_env + absl_spinlock_wait + absl_stacktrace + absl_status + absl_statusor + absl_str_format_internal + absl_strerror + absl_string_view + absl_strings + absl_strings_internal + absl_symbolize + absl_synchronization + absl_throw_delegate + absl_time + absl_time_zone + absl_tracing_internal + absl_utf8_for_code_point + absl_vlog_config_internal +) +set(ABSEIL_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libabseil_combined.a") +combine_static_libs(filament-abseil "${ABSEIL_COMBINED_OUTPUT}" "${ABSEIL_DEPS}") + +set(ABSEIL_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}abseil${CMAKE_STATIC_LIBRARY_SUFFIX}) +install(FILES "${ABSEIL_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${ABSEIL_LIB_NAME}) diff --git a/third_party/abseil/tnt/dummy.c b/third_party/abseil/tnt/dummy.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/matinfo/src/main.cpp b/tools/matinfo/src/main.cpp index ea2d1a014123..cf59f7bb69f4 100644 --- a/tools/matinfo/src/main.cpp +++ b/tools/matinfo/src/main.cpp @@ -422,7 +422,8 @@ static bool parseChunks(Config config, void* data, size_t size) { if (config.serverPort) { // Spin up a web server on a secondary thread. - DebugServer server(Backend::DEFAULT, config.serverPort); + DebugServer server(Backend::DEFAULT, filament::backend::ShaderLanguage::ESSL3, + config.serverPort); if (!server.isReady()) { return false; } diff --git a/web/filament-js/package.json b/web/filament-js/package.json index bf1aec9263a3..cf0635340037 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.56.8", + "version": "1.57.0", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",