Compare commits

..
Author SHA1 Message Date
Benjamin Doherty e9f4433324 OpenGL: handle glFenceSync returning null 2025-02-06 10:25:32 -08:00
Ben Doherty 05cdeccc27 Stop precaching stereo depth variants on non-supported platforms (#8413) 2025-02-05 11:05:03 -08:00
Mathias Agopian ad4f349f00 Improve external texture image API
The current API used a void* in Texture::setExternalImage to pass
the platform specific image. This was a problem because on some
platform like Android, there could be several types (EGLImageKHR and
AHardwareBuffer), and with the void* there was no way to distinguish
them on the backend / platform side.

We now have a new Texture API which takes a
Platform::ExternalImageHandle, which is a reference-counted handle
to a Platform::ExternalImage. Platform::ExternalImage is an opaque
type only known by the platform.

This type must be created using a concrete Platform specific API, such
as:

PlatformEGL::createExternalImage
PlatformEGLAndroid::createExternalImage
PlatformCocoaGL::createExternalImage
PlatformCocoaTouchGL::createExternalImage

New types can easily be added in the future.

There is no "destroy" call because the Platform::ExternalImageHandle is
reference-counted and the client can let go of it as soon as it
doesn't need it any longer (typically after calling
Texture::setExternalImage). Platform::ExternalImage is a small
structure that just anonymously wraps the concrete types.

New internal driver APIs have been added to handle this functionality.
2025-02-04 13:16:56 -08:00
Mathias Agopian 06a2def85f make sure FXAA resets alpha channel when it's the last postfx (#8412)
If FXAA is the last post process effect (i.e. no upscaling), and
color grading produced a luma channel, then FXAA needs to reset the
alpha channel to 1.
2025-02-04 19:52:37 +00:00
Powei Feng a04019937e Add feature flag for material/instance destroy assert (#8411)
This will allow a more lenient rollout of the assertion, which
otherwise will increase crashes for current clients.

We also disable features.engine.debug.assert_material_instance_in_use
by default (it was enabled for debug builds).
2025-02-04 19:30:40 +00:00
Ben Doherty fff7bd2b28 Combine and install Abseil (#8387) 2025-02-04 09:32:49 -08:00
Powei Feng 3c4591df17 java: must use return var in Engine (#8409) 2025-02-03 22:53:44 -08:00
Sungun Park 4fe852e88a Ensure correct resource cleanup sequence to avoid crashes upon app closing (#8408)
The commit 1747ae8f5a enfoces a correct
order for releasing resource. Fix the order to avoid crashes.

Make some samples to use the DEPTH32F format for better compatibility.
Some manufacturers don't fully support DEPTH24 on Vulkan. E.g., AMD
Radeon PRO W6400
2025-02-03 21:23:53 +00:00
Mathias Agopian 864529254e fix color grading as subpass
This broke in 48a2c64. Fixes #8401.
2025-02-03 12:37:53 -08:00
Powei Feng 93fa55bd29 vk: refactor utils into its own namespace (#8280)
We move the code that was contained within two "utils" files
into separate utils sources in the vulkan/utils directory.
2025-02-03 19:10:19 +00:00
Sungun Park fb9518e915 Fix warnings regarding #pragma clang (#8405)
'#pragma clang' is unavailable in MSVC. Wrap them with the proper
preprocessor to avoid warnings in MSVC.

BUGS=[390207431]
2025-02-03 17:43:44 +00:00
Mathias Agopian b780cb36d0 attempt to fix crashers when initializing the JVM
- clarify precondition for VirtualMachineEnv, in particular, 
  JNI_OnLoad() must be called from a thread attached to the VM, and
  should be called once. This is now enforced internally, subsequent
  calls are ignored.

- sVirtualMachine was written and read from potentially different 
  threads without synchronization. It is now mutex protected.

- added fatal asserts in all locations that we cannot recover from;
  previously we would stay in an undefined state.

BUGS=[390724273]
2025-02-01 22:35:53 -08:00
Rafael Dominguez 62cd8f1d35 Update multiview shader code generator for Vulkan
When targeting Vulkan with multiview, the shader
code generator was using the OpenGL extension
and built-in variables, which are not supported on
Vulkan.

Changed it to use GL_EXT_multiview instead of
GL_OVR_multiview2 when the target API is Vulkan.
2025-01-31 16:50:02 -08:00
Doris Wu 793f2b4eb7 [Depends on #8332] Integrate fgviewer to the engine side (#8344)
* Introduce FrameGraphInfo class

* Move the assignment into pimpl

* Make ctors explicit

* Add ctors to fg info structs

* Revert the macro change to align with existing

* Address the comments

* Remove pimpl and move func def to .cc

* Fix

* Convert the FrameGraph to FrameGraphInfo

* Initialize and update debug server on engine side

* Fix compile error

* Address the comments

* Update

* Use camelCase

* Use camelCase

* Update
2025-01-31 23:39:47 +00:00
Ben Doherty 9a2ca8ddbb Metal: add config to abandon frame if drawable cannot be acquired (#8397) 2025-01-31 13:31:07 -08:00
Eliza Velasquez 67710723d7 c-filament-style.el: fix init list indent 2025-01-31 12:06:09 -08:00
Eliza Velasquez 40851f4b51 matdbg: add support for essl1 shader debugging
Fixes #8261
2025-01-31 11:44:51 -08:00
Sungun Park 87bdf96449 Refactor: Rename shader snippets w/ new naming convention (see README.md) (#8402)
This commit renames all shader snippet files to conform to the newly
introduced naming convention outlined in README.md.

The new naming convention uses a `prefix_name.suffix` format to clearly
indicate the purpose and target shader stage of each snippet. This
improves the overall organization and readability of the shader code,
making it easier to understand how each snippet contributes to the
shader generation process.

No functional changes were made to the shader code itself or source
code. This is purely a refactoring for clarity and maintainability.
2025-01-31 00:02:53 +00:00
156 changed files with 2054 additions and 1131 deletions
+17 -10
View File
@@ -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)
+3
View File
@@ -7,3 +7,6 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- matdbg: Add support for debugging ESSL 1.0 shaders
- backend: New platform API to better handle external textures [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.56.8'
implementation 'com.google.android.filament:filament-android:1.56.7'
}
```
@@ -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.56.7'
```
## Documentation
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.56.8
VERSION_NAME=1.56.7
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
-39
View File
@@ -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% ^<path-to-ar^> ^<output-archive^> ^<archives^>...
echo;
echo Notes:
echo ^<archives^> 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%
+4 -4
View File
@@ -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
)
+9 -6
View File
@@ -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)
@@ -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,
@@ -25,6 +25,8 @@
#include <stddef.h>
#include <stdint.h>
#include <atomic>
namespace filament::backend {
class Driver;
@@ -41,6 +43,46 @@ public:
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;
};
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.)
@@ -51,10 +51,9 @@ protected:
~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
};
/**
@@ -324,36 +323,45 @@ public:
* 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.
@@ -34,12 +34,14 @@ public:
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 +61,12 @@ protected:
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;
@@ -32,11 +32,13 @@ public:
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 @@ public:
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;
@@ -47,6 +47,11 @@ public:
// 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
@@ -118,9 +123,10 @@ protected:
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 +194,12 @@ protected:
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;
@@ -57,6 +57,11 @@ protected:
Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
/**
* Creates an ExternalImage from a EGLImageKHR
*/
ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept;
// --------------------------------------------------------------------------------------------
// OpenGLPlatform Interface
@@ -89,6 +94,15 @@ protected:
*/
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,
@@ -69,6 +69,16 @@ public:
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;
@@ -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
@@ -18,7 +18,7 @@
#define TNT_FILAMENT_DRIVER_ANDROID_VIRTUAL_MACHINE_ENV_H
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Mutex.h>
#include <jni.h>
@@ -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<void**>(&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 @@ public:
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;
};
+85
View File
@@ -16,8 +16,93 @@
#include <backend/Platform.h>
#include <utils/compiler.h>
#include <atomic>
#include <utility>
#include <stddef.h>
#include <stdint.h>
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;
}
// --------------------------------------------------------------------------------------------------------------------
Platform::ExternalImage::~ExternalImage() noexcept = default;
// --------------------------------------------------------------------------------------------------------------------
Platform::Platform() noexcept = default;
// this generates the vtable in this translation unit
+81 -16
View File
@@ -18,12 +18,28 @@
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Mutex.h>
#include <utils/Panic.h>
#include <jni.h>
#include <mutex>
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,15 +51,75 @@ 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<void**>(&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<void**>(&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
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<void**>(&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__)
jint const result = mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr);
#else
jint const result = mVirtualMachine->AttachCurrentThread(reinterpret_cast<void**>(&mJniEnv), nullptr);
#endif
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())) {
@@ -52,16 +128,5 @@ void VirtualMachineEnv::handleException(JNIEnv* const env) noexcept {
}
}
UTILS_NOINLINE
JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept {
#if defined(__ANDROID__)
mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr);
#else
mVirtualMachine->AttachCurrentThread(reinterpret_cast<void**>(&mJniEnv), nullptr);
#endif
assert_invariant(mJniEnv);
return mJniEnv;
}
} // namespace filament
+1
View File
@@ -67,6 +67,7 @@ private:
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<void(void)> const& fn) noexcept final;
+22 -2
View File
@@ -513,6 +513,14 @@ void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTextu
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
}
void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> 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<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
@@ -747,6 +755,10 @@ Handle<HwTexture> MetalDriver::createTextureViewSwizzleS() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureExternalImage2S() noexcept {
return alloc_handle<MetalTexture>();
}
Handle<HwTexture> MetalDriver::createTextureExternalImageS() noexcept {
return alloc_handle<MetalTexture>();
}
@@ -947,6 +959,10 @@ ShaderModel MetalDriver::getShaderModel() const noexcept {
#endif
}
ShaderLanguage MetalDriver::getShaderLanguage() const noexcept {
return ShaderLanguage::MSL;
}
Handle<HwStream> MetalDriver::createStreamNative(void* stream) {
return {};
}
@@ -1135,8 +1151,8 @@ FeatureLevel MetalDriver::getFeatureLevel() {
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 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
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
+11
View File
@@ -17,6 +17,10 @@
#include "noop/NoopDriver.h"
#include "CommandStreamDispatcher.h"
#include <backend/Handle.h>
#include <stdint.h>
namespace filament::backend {
Driver* NoopDriver::create() {
@@ -39,6 +43,10 @@ ShaderModel NoopDriver::getShaderModel() const noexcept {
#endif
}
ShaderLanguage NoopDriver::getShaderLanguage() const noexcept {
return ShaderLanguage::ESSL3;
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<NoopDriver>;
@@ -258,6 +266,9 @@ void NoopDriver::update3DImage(Handle<HwTexture> th,
scheduleDestroy(std::move(data));
}
void NoopDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
}
void NoopDriver::setupExternalImage(void* image) {
}
+1
View File
@@ -34,6 +34,7 @@ public:
private:
ShaderModel getShaderModel() const noexcept final;
ShaderLanguage getShaderLanguage() const noexcept final;
uint64_t nextFakeHandle = 1;
+44 -23
View File
@@ -18,6 +18,7 @@
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <backend/DriverEnums.h>
@@ -25,6 +26,8 @@
#include <string_view>
#include <unordered_set>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#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<GLenum, GLenum> textureFormatToFormatAndType(
constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
TextureFormat format) noexcept {
switch (format) {
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
+88 -22
View File
@@ -75,9 +75,11 @@
#include <emscripten.h>
#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
@@ -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<HwTexture> OpenGLDriver::createTextureViewSwizzleS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureExternalImage2S() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureExternalImageS() noexcept {
return initHandle<GLTexture>();
}
@@ -897,25 +907,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> 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<HwTexture> th,
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> 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<GLTexture const*>(srch);
@@ -1052,6 +1043,57 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> 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<GLTexture>(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<HwTexture> 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<HwTexture> 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<HwTexture> 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);
}
@@ -3433,6 +3489,14 @@ void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) noexcept {
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// glFenceSync can return 0 in certain situations. For example, we've seen this happen on Web
// when the GL context has been lost.
// Unfortunately, there's not much we can do here. The fn callback will never execute, which
// could cause issues. If we've lost the WebGL context though, Filament is most likely shutting
// down anyway, so in practice this might not be a big problem.
if (!sync) {
return;
}
mGpuCommandCompleteOps.emplace_back(sync, fn);
CHECK_GL_ERROR(utils::slog.e)
}
@@ -4090,4 +4154,6 @@ template class ConcreteDispatcher<OpenGLDriver>;
} // namespace filament::backend
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
@@ -204,6 +204,7 @@ private:
}
ShaderModel getShaderModel() const noexcept final;
ShaderLanguage getShaderLanguage() const noexcept final;
/*
* Driver interface
+11 -1
View File
@@ -121,14 +121,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 {
@@ -16,13 +16,28 @@
#include "ExternalStreamManagerAndroid.h"
#include <utils/api_level.h>
#include <private/backend/VirtualMachineEnv.h>
#include <backend/Platform.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <dlfcn.h>
#if __has_include(<android/surface_texture.h>)
# include <android/surface_texture.h>
# include <android/surface_texture_jni.h>
#else
struct ASurfaceTexture;
typedef struct ASurfaceTexture ASurfaceTexture;
#endif
#include <chrono>
#include <jni.h>
#include <stdint.h>
#include <new>
using namespace utils;
@@ -32,13 +47,8 @@ using namespace backend;
using Stream = Platform::Stream;
template <typename T>
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<EGLStream*>(handle);
EGLStream const* stream = static_cast<EGLStream*>(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<EGLStream*>(handle);
EGLStream const* stream = static_cast<EGLStream*>(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<EGLStream*>(handle);
EGLStream const* stream = static_cast<EGLStream*>(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);
@@ -21,14 +21,19 @@
#include <backend/Platform.h>
#include <utils/compiler.h>
#if __has_include(<android/surface_texture.h>)
# include <android/surface_texture.h>
# include <android/surface_texture_jni.h>
#else
struct ASurfaceTexture;
typedef struct ASurfaceTexture ASurfaceTexture;
#endif
#include <jni.h>
#include <stdint.h>
namespace filament::backend {
/*
@@ -70,7 +75,8 @@ private:
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 @@ private:
jmethodID mSurfaceTextureClass_attachToGLContext{};
jmethodID mSurfaceTextureClass_detachFromGLContext{};
};
} // namespace filament::backend
#endif //TNT_FILAMENT_BACKEND_OPENGL_ANDROID_EXTERNAL_STREAM_MANAGER_ANDROID_H
@@ -54,8 +54,15 @@ struct PlatformCocoaGLImpl {
CVOpenGLTextureCacheRef mTextureCache = nullptr;
std::unique_ptr<CocoaExternalImage::SharedGl> 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 @@ OpenGLPlatform::ExternalTexture* PlatformCocoaGL::createExternalImageTexture() n
if (!pImpl->mExternalImageSharedGl) {
pImpl->mExternalImageSharedGl = std::make_unique<CocoaExternalImage::SharedGl>();
}
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<CocoaExternalImage*>(texture);
delete p;
}
@@ -344,6 +346,36 @@ bool PlatformCocoaGL::setExternalImage(void* externalImage, ExternalTexture* tex
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<PlatformCocoaGLImpl::ExternalImageCocoaGL const*>(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<PlatformCocoaGLImpl::ExternalImageCocoaGL const*>(externalImage.get());
CVPixelBufferRef cvPixelBuffer = cocoaGlExternalImage->cvBuffer;
CocoaExternalImage* cocoaExternalImage = static_cast<CocoaExternalImage*>(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;
@@ -47,8 +47,15 @@ struct PlatformCocoaTouchGLImpl {
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 @@ void PlatformCocoaTouchGL::commit(Platform::SwapChain* swapChain) noexcept {
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<CocoaTouchExternalImage*>(texture);
delete p;
}
@@ -229,4 +233,35 @@ bool PlatformCocoaTouchGL::setExternalImage(void* externalImage, ExternalTexture
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<PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL const*>(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<PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL const*>(externalImage.get());
CVPixelBufferRef cvPixelBuffer = cocoaTouchGlExternalImage->cvBuffer;
CocoaTouchExternalImage* cocoaExternalImage = static_cast<CocoaTouchExternalImage*>(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
@@ -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);
@@ -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<ExternalImageEGL const*>(externalImage.get());
return setExternalImage(eglExternalImage->eglImage, texture);
}
// -----------------------------------------------------------------------------------------------
void PlatformEGL::initializeGlExtensions() noexcept {
@@ -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<AHardwareBuffer*>(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<ExternalImageEGLAndroid const*>(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) {
@@ -21,6 +21,7 @@
#include "VulkanHandles.h"
#include "VulkanSamplerCache.h"
#include "VulkanTexture.h"
#include "vulkan/utils/Image.h"
#include <utils/FixedCapacityVector.h>
#include <utils/Panic.h>
@@ -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) {
+3 -3
View File
@@ -23,8 +23,8 @@
#include "VulkanAsyncHandles.h"
#include "VulkanConstants.h"
#include "VulkanUtility.h"
#include "vulkan/memory/ResourcePointer.h"
#include "vulkan/utils/StaticVector.h"
#include <utils/Condition.h>
#include <utils/FixedCapacityVector.h>
@@ -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 @@ private:
bool const isProtected;
VkDevice mDevice;
VkQueue mQueue;
CappedArray<VkSemaphore, 2> mWaitSemaphores;
fvkutils::StaticVector<VkSemaphore, 2> mWaitSemaphores;
VkCommandBuffer mBuffer;
VkSemaphore mSubmission;
VkFence mFence;
@@ -20,7 +20,6 @@
#include "VulkanHandles.h"
#include "VulkanMemory.h"
#include "VulkanTexture.h"
#include "VulkanUtility.h"
#include <backend/PixelBufferDescriptor.h>
+8 -6
View File
@@ -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 <utils/Mutex.h>
#include <utils/Slice.h>
#include <bluevk/BlueVK.h>
#include <memory>
VK_DEFINE_HANDLE(VmaAllocator)
@@ -113,11 +115,11 @@ public:
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 @@ private:
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;
+49 -23
View File
@@ -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 <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatform.h>
#include <utils/CString.h>
@@ -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<HwTexture> th, Handle<HwText
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a) {
TextureSwizzle const swizzleArray[] = {r, g, b, a};
VkComponentMapping const swizzle = getSwizzleMap(swizzleArray);
VkComponentMapping const swizzle = fvkutils::getSwizzleMap(swizzleArray);
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle);
texture.inc();
}
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th,
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> 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<HwTexture> 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<HwTexture> 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<HwTexture> VulkanDriver::createTextureViewSwizzleS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureExternalImage2S() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
Handle<HwTexture> VulkanDriver::createTextureExternalImageS() noexcept {
return mResourceManager.allocHandle<VulkanTexture>();
}
@@ -930,7 +952,7 @@ FenceStatus VulkanDriver::getFenceStatus(Handle<HwFence> 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<HwTexture> 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<VulkanDriver>;
} // namespace filament::backend
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
+10 -7
View File
@@ -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 @@ private:
Dispatcher getDispatcher() const noexcept final;
ShaderModel getShaderModel() const noexcept final;
ShaderLanguage getShaderLanguage() const noexcept final;
template<typename T>
friend class ConcreteDispatcher;
@@ -141,13 +143,14 @@ private:
struct {
resource_ptr<VulkanProgram> 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<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
using AttachmentArray =
fvkutils::StaticVector<VulkanAttachment, MAX_RENDERTARGET_ATTACHMENT_TEXTURES>;
AttachmentArray attachments;
} mRenderPassFboInfo = {};
+13 -13
View File
@@ -14,12 +14,12 @@
* limitations under the License.
*/
#include "vulkan/VulkanFboCache.h"
#include <utils/Panic.h>
#include "VulkanFboCache.h"
#include "VulkanConstants.h"
#include "VulkanUtility.h"
#include "vulkan/utils/Image.h"
#include <utils/Panic.h>
// 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;
+10 -8
View File
@@ -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 <backend/platforms/VulkanPlatform.h>
@@ -56,10 +58,10 @@ template<typename Bitmask>
inline void fromStageFlags(backend::ShaderStageFlags stage, descriptor_binding_t binding,
Bitmask& mask) {
if ((bool) (stage & ShaderStageFlags::VERTEX)) {
mask.set(binding + getVertexStageShift<Bitmask>());
mask.set(binding + fvkutils::getVertexStageShift<Bitmask>());
}
if ((bool) (stage & ShaderStageFlags::FRAGMENT)) {
mask.set(binding + getFragmentStageShift<Bitmask>());
mask.set(binding + fvkutils::getFragmentStageShift<Bitmask>());
}
}
@@ -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
+13 -12
View File
@@ -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 <backend/Program.h>
@@ -44,11 +45,11 @@ namespace {
template<typename Bitmask>
inline uint8_t collapsedCount(Bitmask const& mask) {
static_assert(sizeof(mask) <= 64);
constexpr uint64_t VERTEX_MASK = (1ULL << getFragmentStageShift<Bitmask>()) - 1ULL;
constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << getFragmentStageShift<Bitmask>());
constexpr uint64_t VERTEX_MASK = (1ULL << fvkutils::getFragmentStageShift<Bitmask>()) - 1ULL;
constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << fvkutils::getFragmentStageShift<Bitmask>());
uint64_t val = mask.getValue();
val = ((val & VERTEX_MASK) >> getVertexStageShift<Bitmask>()) |
((val & FRAGMENT_MASK) >> getFragmentStageShift<Bitmask>());
val = ((val & VERTEX_MASK) >> fvkutils::getVertexStageShift<Bitmask>()) |
((val & FRAGMENT_MASK) >> fvkutils::getFragmentStageShift<Bitmask>());
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 @@ public:
using OnRecycle = std::function<void(VulkanDescriptorSet*)>;
VulkanDescriptorSet(VkDescriptorSet rawSet,
UniformBufferBitmask const& dynamicUboMask,
fvkutils::UniformBufferBitmask const& dynamicUboMask,
uint8_t uniqueDynamicUboCount,
OnRecycle&& onRecycleFn)
: vkSet(rawSet),
@@ -164,7 +165,7 @@ public:
void acquire(fvkmemory::resource_ptr<VulkanBufferObject> buffer);
VkDescriptorSet const vkSet;
UniformBufferBitmask const dynamicUboMask;
fvkutils::UniformBufferBitmask const dynamicUboMask;
uint8_t const uniqueDynamicUboCount;
private:
@@ -193,7 +194,7 @@ private:
};
struct VulkanProgram : public HwProgram, fvkmemory::Resource {
using BindingList = CappedArray<uint16_t, MAX_SAMPLER_COUNT>;
using BindingList = fvkutils::StaticVector<uint16_t, MAX_SAMPLER_COUNT>;
VulkanProgram(VkDevice device, Program const& builder) noexcept;
~VulkanProgram();
@@ -16,6 +16,7 @@
#include <bluevk/BlueVK.h> // 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
@@ -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"
@@ -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
@@ -19,7 +19,6 @@
#include "VulkanCommands.h"
#include "VulkanMemory.h"
#include "VulkanUtility.h"
#include <backend/DriverEnums.h>
#include <backend/TargetBufferInfo.h>
@@ -68,8 +67,10 @@ public:
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 @@ private:
bool operator()(const PipelineKey& k1, const PipelineKey& k2) const;
};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
// CACHE ENTRY STRUCTS
// -------------------
@@ -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 <utils/Log.h>
@@ -218,7 +219,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> 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<VulkanRenderTarget> 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<VulkanRenderTarget> 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<int>(subResourceLayout.rowPitch), static_cast<int>(width),
static_cast<int>(height), swizzle)) {
FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
@@ -15,6 +15,7 @@
*/
#include "vulkan/VulkanSamplerCache.h"
#include "vulkan/utils/Conversion.h"
#include <utils/Panic.h>
@@ -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,
@@ -18,7 +18,6 @@
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
#include "VulkanContext.h"
#include "VulkanUtility.h"
#include <tsl/robin_map.h>
@@ -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 <utils/Panic.h>
@@ -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)
+22 -20
View File
@@ -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 <DataReshaper.h>
#include <backend/DriverEnums.h>
@@ -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<VulkanTextureState>::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<VulkanTextureState>::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,
+1 -1
View File
@@ -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 <utils/Hash.h>
#include <utils/RangeMap.h>
@@ -16,11 +16,10 @@
#include "VulkanDescriptorSetManager.h"
#include <vulkan/VulkanCommands.h>
#include <vulkan/VulkanHandles.h>
#include <vulkan/VulkanUtility.h>
#include <vulkan/VulkanConstants.h>
#include <vulkan/VulkanImageUtility.h>
#include "vulkan/VulkanCommands.h"
#include "vulkan/VulkanHandles.h"
#include "vulkan/VulkanConstants.h"
#include <utils/FixedCapacityVector.h>
#include <utils/Panic.h>
@@ -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<Bitmask>()) {
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
binding = (uint32_t) index;
stages |= VK_SHADER_STAGE_VERTEX_BIT;
auto fragIndex = index + getFragmentStageShift<Bitmask>();
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
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<Bitmask>());
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
}
@@ -346,7 +345,6 @@ private:
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_ptr<VulkanDes
} else {
info.imageView = texture->getViewForType(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,
@@ -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 <backend/DriverEnums.h>
#include <backend/Program.h>
@@ -68,7 +67,7 @@ public:
void unbind(uint8_t setIndex);
void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
DescriptorSetMask const& setMask);
fvkutils::DescriptorSetMask const& setMask);
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
@@ -93,7 +92,7 @@ private:
struct {
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
DescriptorSetMask setMask;
fvkutils::DescriptorSetMask setMask;
DescriptorSetArray boundSets = {};
} mLastBoundInfo;
};
@@ -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 <bluevk/BlueVK.h>
#include <utils/PrivateImplementation-impl.h>
@@ -126,7 +126,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
const int minor = VK_VERSION_MINOR(deviceProperties.apiVersion);
const FixedCapacityVector<VkPhysicalDevice> 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<VkExtensionProperties> const availableExts =
filament::backend::enumerate(vkEnumerateInstanceExtensionProperties,
fvkutils::enumerate(vkEnumerateInstanceExtensionProperties,
static_cast<char const*>(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<VkExtensionProperties> const extensions
= filament::backend::enumerate(vkEnumerateDeviceExtensionProperties, device,
= fvkutils::enumerate(vkEnumerateDeviceExtensionProperties, device,
static_cast<const char*>(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<VkPhysicalDevice> 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<VkExtensionProperties> const extensions
= filament::backend::enumerate(vkEnumerateDeviceExtensionProperties,
= fvkutils::enumerate(vkEnumerateDeviceExtensionProperties,
candidateDevice, static_cast<char const*>(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<VkFormat> 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;
}
@@ -199,7 +199,6 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkGetAndroidHardwareBufferProperties failed with error="
<< static_cast<int32_t>(result);
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format)
<< "mismatched image format for external image (AHB)";
metadata.externalFormat = formatInfo.externalFormat;
@@ -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 <backend/DriverEnums.h>
@@ -29,9 +31,8 @@ namespace filament::backend {
namespace {
std::tuple<VkImage, VkDeviceMemory> 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<VkImage, VkDeviceMemory> 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<VkSurfaceFormatKHR> const surfaceFormats
= enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface);
= fvkutils::enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface);
std::array<VkFormat, 2> 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<VkPresentModeKHR> presentModes
= enumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, mPhysicalDevice, mSurface);
FixedCapacityVector<VkPresentModeKHR> 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<int32_t>(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() {
@@ -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 <utils/algorithm.h>
#include <utils/debug.h>
#include <utils/Panic.h>
#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
@@ -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 <backend/DriverEnums.h>
#include <private/backend/BackendUtils.h> // for getFormatSize()
#include <bluevk/BlueVK.h>
// 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
@@ -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 <backend/DriverEnums.h>
#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H
#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <bluevk/BlueVK.h>
#include <utility>
// Definitions for common types used across classes.
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<OutType> 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 <typename OutType>
utils::FixedCapacityVector<OutType> enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) {
EXPAND_ENUM_NO_ARGS();
}
template <typename InType, typename OutType>
utils::FixedCapacityVector<OutType> enumerate(
VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) {
EXPAND_ENUM_ARGS(inData);
}
template <typename InTypeA, typename InTypeB, typename OutType>
utils::FixedCapacityVector<OutType> 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 {
// Useful shorthands
using VkFormatList = utils::FixedCapacityVector<VkFormat>;
@@ -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<typename T, uint16_t CAPACITY>
class CappedArray {
private:
using FixedSizeArray = std::array<T, CAPACITY>;
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
@@ -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 <backend/DriverEnums.h>
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <bluevk/BlueVK.h>
#include <utility>
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<OutType> 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 <typename OutType>
utils::FixedCapacityVector<OutType> enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) {
EXPAND_ENUM_NO_ARGS();
}
template <typename InType, typename OutType>
utils::FixedCapacityVector<OutType> enumerate(
VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) {
EXPAND_ENUM_ARGS(inData);
}
template <typename InTypeA, typename InTypeB, typename OutType>
utils::FixedCapacityVector<OutType> 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
@@ -14,9 +14,9 @@
* limitations under the License.
*/
#include "VulkanImageUtility.h"
#include "vulkan/utils/Image.h"
#include "VulkanTexture.h"
#include "vulkan/VulkanTexture.h"
#include <utils/Panic.h>
#include <utils/algorithm.h>
@@ -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;
@@ -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 <backend/DriverEnums.h>
@@ -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
@@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "VulkanSpirvUtils.h"
#include "vulkan/utils/Spirv.h"
#include <utils/compiler.h> // UTILS_UNUSED_IN_RELEASE, UTILS_FALLTHROUGH
#include <utils/debug.h> // assert_invariant
@@ -22,12 +22,11 @@
#include <spirv/unified1/spirv.hpp>
#include <unordered_map>
#include <variant>
#include <vector>
#include <cstring>
#include <unordered_map>
#include <vector>
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<uint32_t,uint32_t, uint32_t> getProgramBindings(Program::ShaderBlob const& blob) {
std::unordered_map<uint32_t, uint32_t> 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
@@ -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 <backend/Program.h>
@@ -24,7 +24,7 @@
#include <tuple>
#include <vector>
namespace filament::backend {
namespace filament::backend::fvkutils {
using SpecConstantValue = Program::SpecializationConstant::Type;
@@ -44,8 +44,9 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob,
std::vector<uint32_t>& output);
// bindings for UBO, samplers, input attachment
std::tuple<uint32_t, uint32_t, uint32_t> getProgramBindings(Program::ShaderBlob const& blob);
// This is no longer needed after the descriptor set refactor, but the code is good for reference.
// std::tuple<uint32_t, uint32_t, uint32_t> 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
@@ -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 <utils/Panic.h>
#include <array>
namespace filament::backend::fvkutils {
template<typename T, uint16_t CAPACITY>
class StaticVector {
private:
using FixedSizeArray = std::array<T, CAPACITY>;
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
+47 -22
View File
@@ -23,6 +23,7 @@
#include <backend/DriverEnums.h>
#include <backend/PixelBufferDescriptor.h>
#include <backend/Platform.h>
#include <utils/compiler.h>
@@ -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 @@ public:
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 @@ public:
*/
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 @@ public:
*/
Builder& import(intptr_t id) noexcept;
/**
* Creates an external texture. The content must be set using setExternalImage().
* The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally
* YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not
* validated.
*
* If the Sampler is set to SAMPLER_EXTERNAL, external() is implied.
*
* @return
*/
Builder& external() noexcept;
private:
friend class FTexture;
};
@@ -359,7 +362,7 @@ public:
* 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 @@ public:
* 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 @@ public:
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 @@ public:
*
* @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 @@ public:
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 @@ public:
* @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 @@ public:
* @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,
+8
View File
@@ -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
+2
View File
@@ -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);
}
+1 -1
View File
@@ -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;
}
+3 -3
View File
@@ -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 };
+4
View File
@@ -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);
}
+4
View File
@@ -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;
+14
View File
@@ -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<TextureFormat, PixelDataFormat, PixelDataType>
}
}
#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));
+41 -22
View File
@@ -706,28 +706,6 @@ int FEngine::loop() {
}
}
#if FILAMENT_ENABLE_MATDBG
#ifdef __ANDROID__
const char* portString = "8081";
#else
const char* portString = getenv("FILAMENT_MATDBG_PORT");
#endif
if (portString != nullptr) {
const int port = atoi(portString);
debug.server = new matdbg::DebugServer(mBackend, 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.
if (!debug.server->isReady()) {
delete debug.server;
debug.server = nullptr;
} else {
debug.server->setEditCallback(FMaterial::onEditCallback);
debug.server->setQueryCallback(FMaterial::onQueryCallback);
}
}
#endif
JobSystem::setThreadName("FEngine::loop");
JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
@@ -749,6 +727,47 @@ int FEngine::loop() {
return 0;
}
#if FILAMENT_ENABLE_MATDBG
#ifdef __ANDROID__
const char* portString = "8081";
#else
const char* portString = getenv("FILAMENT_MATDBG_PORT");
#endif
if (portString != nullptr) {
const int port = atoi(portString);
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.
if (!debug.server->isReady()) {
delete debug.server;
debug.server = nullptr;
} else {
debug.server->setEditCallback(FMaterial::onEditCallback);
debug.server->setQueryCallback(FMaterial::onQueryCallback);
}
}
#endif
#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);
// 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()) {
break;
+11 -10
View File
@@ -88,6 +88,14 @@ using MaterialKey = uint32_t;
} // namespace filament::matdbg
#endif
#if FILAMENT_ENABLE_FGVIEWER
#include <fgviewer/DebugServer.h>
#else
namespace filament::fgviewer {
class DebugServer;
} // namespace filament::fgviewer
#endif
namespace filament {
class Renderer;
@@ -252,20 +260,12 @@ public:
// Return a vector of shader languages, in order of preference.
utils::FixedCapacityVector<backend::ShaderLanguage> 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 };
}
@@ -681,6 +681,7 @@ public:
bool combine_multiview_images = false;
} stereo;
matdbg::DebugServer* server = nullptr;
fgviewer::DebugServer* fgviewerServer = nullptr;
} debug;
struct {
+5
View File
@@ -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);
+1 -1
View File
@@ -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 {
+8 -1
View File
@@ -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);
+1 -1
View File
@@ -174,7 +174,7 @@ void FSkinningBuffer::setBones(FEngine& engine, Handle<HwBufferObject> 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 {
+20
View File
@@ -469,6 +469,26 @@ void FTexture::setImage(FEngine& engine, size_t const level,
const_cast<FTexture*>(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.";
+1
View File
@@ -66,6 +66,7 @@ public:
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;
+15
View File
@@ -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 {
+14
View File
@@ -60,6 +60,14 @@
#include <utils/Range.h>
#include <utils/Slice.h>
#if FILAMENT_ENABLE_FGVIEWER
#include <fgviewer/DebugServer.h>
#else
namespace filament::fgviewer {
using ViewHandle = uint32_t;
}
#endif
#include <math/scalar.h>
#include <math/mat4.h>
@@ -467,6 +475,10 @@ public:
return mUniforms;
}
fgviewer::ViewHandle getViewHandle() const noexcept {
return mFrameGraphViewerViewHandle;
}
private:
struct FPickingQuery : public PickingQuery {
private:
@@ -600,6 +612,8 @@ private:
{ 0, 0, 0, 1 },
}};
fgviewer::ViewHandle mFrameGraphViewerViewHandle;
#ifndef NDEBUG
struct DebugState {
std::unique_ptr<std::array<DebugRegistry::FrameHistory, 5*60>> debugFrameHistory{};
+55
View File
@@ -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<fgviewer::FrameGraphInfo::Pass> passes;
auto first = mPassNodes.begin();
const auto activePassNodesEnd = mActivePassNodesEnd;
while (first != activePassNodesEnd) {
PassNode *const pass = *first;
first++;
assert_invariant(!pass->isCulled());
std::vector<fgviewer::ResourceId> 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<fgviewer::ResourceId> 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<fgviewer::ResourceId, fgviewer::FrameGraphInfo::Resource> resources;
for (const auto &resource: mResourceNodes) {
std::vector<fgviewer::FrameGraphInfo::Resource::Property> 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
}
// ------------------------------------------------------------------------------------------------
/*
+14
View File
@@ -36,6 +36,14 @@
#include <functional>
#if FILAMENT_ENABLE_FGVIEWER
#include <fgviewer/FrameGraphInfo.h>
#else
namespace filament::fgviewer {
class FrameGraphInfo{};
} // namespace filament::fgviewer
#endif
namespace filament {
class ResourceAllocatorInterface;
@@ -434,6 +442,12 @@ public:
//! 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;
+4
View File
@@ -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,
@@ -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(){}
@@ -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(){}
+2 -1
View File
@@ -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)
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.56.8"
spec.version = "1.56.7"
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.56.7/filament-v1.56.7-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -31,8 +31,6 @@ namespace filament::fgviewer {
using ViewHandle = uint32_t;
/**
* Server-side frame graph debugger.
*
@@ -727,7 +727,7 @@ public:
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.
+6 -6
View File
@@ -937,15 +937,15 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
// explicitly remove them when using filamat lite.
std::string shader;
if (v.stage == backend::ShaderStage::VERTEX) {
shader = sg.createVertexProgram(
shader = sg.createSurfaceVertexProgram(
shaderModel, targetApi, targetLanguage, featureLevel,
info, v.variant, mInterpolation, mVertexDomain);
} else if (v.stage == backend::ShaderStage::FRAGMENT) {
shader = sg.createFragmentProgram(
shader = sg.createSurfaceFragmentProgram(
shaderModel, targetApi, targetLanguage, featureLevel,
info, v.variant, mInterpolation, mVariantFilter);
} else if (v.stage == backend::ShaderStage::COMPUTE) {
shader = sg.createComputeProgram(
shader = sg.createSurfaceComputeProgram(
shaderModel, targetApi, targetLanguage, featureLevel,
info);
}
@@ -1438,15 +1438,15 @@ std::string MaterialBuilder::peek(backend::ShaderStage stage,
switch (stage) {
case backend::ShaderStage::VERTEX:
return sg.createVertexProgram(
return sg.createSurfaceVertexProgram(
params.shaderModel, params.targetApi, params.targetLanguage,
params.featureLevel, info, {}, mInterpolation, mVertexDomain);
case backend::ShaderStage::FRAGMENT:
return sg.createFragmentProgram(
return sg.createSurfaceFragmentProgram(
params.shaderModel, params.targetApi, params.targetLanguage,
params.featureLevel, info, {}, mInterpolation, mVariantFilter);
case backend::ShaderStage::COMPUTE:
return sg.createComputeProgram(
return sg.createSurfaceComputeProgram(
params.shaderModel, params.targetApi, params.targetLanguage,
params.featureLevel, info);
}
+95 -90
View File
@@ -42,7 +42,7 @@ io::sstream& CodeGenerator::generateSeparator(io::sstream& out) {
return out;
}
utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, ShaderStage stage,
utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, ShaderStage stage,
MaterialInfo const& material, filament::Variant v) const {
switch (mShaderModel) {
case ShaderModel::MOBILE:
@@ -78,7 +78,11 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
out << "#endif\n\n";
break;
case StereoscopicType::MULTIVIEW:
out << "#extension GL_OVR_multiview2 : require\n";
if (mTargetApi == TargetApi::VULKAN) {
out << "#extension GL_EXT_multiview : enable\n";
} else {
out << "#extension GL_OVR_multiview2 : require\n";
}
break;
case StereoscopicType::NONE:
break;
@@ -101,7 +105,11 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
// Nothing to generate
break;
case StereoscopicType::MULTIVIEW:
out << "#extension GL_OVR_multiview2 : require\n";
if (mTargetApi == TargetApi::VULKAN) {
out << "#extension GL_EXT_multiview : enable\n";
} else {
out << "#extension GL_OVR_multiview2 : require\n";
}
break;
case StereoscopicType::NONE:
break;
@@ -124,7 +132,9 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
// Nothing to generate
break;
case StereoscopicType::MULTIVIEW:
out << "layout(num_views = " << material.stereoscopicEyeCount << ") in;\n";
if (mTargetApi != TargetApi::VULKAN) {
out << "layout(num_views = " << material.stereoscopicEyeCount << ") in;\n";
}
break;
case StereoscopicType::NONE:
break;
@@ -324,7 +334,7 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
+ReservedSpecializationConstants::CONFIG_DEBUG_FROXEL_VISUALIZATION, false);
// 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
generateSpecializationConstant(out, "CONFIG_STATIC_TEXTURE_TARGET_WORKAROUND",
+ReservedSpecializationConstants::CONFIG_STATIC_TEXTURE_TARGET_WORKAROUND, false);
@@ -409,21 +419,21 @@ Precision CodeGenerator::getDefaultUniformPrecision() const {
}
}
io::sstream& CodeGenerator::generateEpilog(io::sstream& out) {
io::sstream& CodeGenerator::generateCommonEpilog(io::sstream& out) {
out << "\n"; // For line compression all shaders finish with a newline character.
return out;
}
io::sstream& CodeGenerator::generateCommonTypes(io::sstream& out, ShaderStage stage) {
io::sstream& CodeGenerator::generateSurfaceTypes(io::sstream& out, ShaderStage stage) {
out << '\n';
switch (stage) {
case ShaderStage::VERTEX:
out << '\n';
out << SHADERS_COMMON_TYPES_GLSL_DATA;
out << SHADERS_SURFACE_TYPES_GLSL_DATA;
break;
case ShaderStage::FRAGMENT:
out << '\n';
out << SHADERS_COMMON_TYPES_GLSL_DATA;
out << SHADERS_SURFACE_TYPES_GLSL_DATA;
break;
case ShaderStage::COMPUTE:
break;
@@ -431,31 +441,31 @@ io::sstream& CodeGenerator::generateCommonTypes(io::sstream& out, ShaderStage st
return out;
}
io::sstream& CodeGenerator::generateShaderMain(io::sstream& out, ShaderStage stage) {
io::sstream& CodeGenerator::generateSurfaceMain(io::sstream& out, ShaderStage stage) {
switch (stage) {
case ShaderStage::VERTEX:
out << SHADERS_MAIN_VS_DATA;
out << SHADERS_SURFACE_MAIN_VS_DATA;
break;
case ShaderStage::FRAGMENT:
out << SHADERS_MAIN_FS_DATA;
out << SHADERS_SURFACE_MAIN_FS_DATA;
break;
case ShaderStage::COMPUTE:
out << SHADERS_MAIN_CS_DATA;
out << SHADERS_SURFACE_MAIN_CS_DATA;
break;
}
return out;
}
io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
out << SHADERS_POST_PROCESS_VS_DATA;
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_POST_PROCESS_FS_DATA;
io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderStage stage) {
if (stage == ShaderStage::VERTEX) {
out << SHADERS_POST_PROCESS_MAIN_VS_DATA;
} else if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_POST_PROCESS_MAIN_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage,
io::sstream& CodeGenerator::generateCommonVariable(io::sstream& out, ShaderStage stage,
const MaterialBuilder::CustomVariable& variable, size_t index) {
auto const& name = variable.name;
const char* precisionString = getPrecisionQualifier(variable.precision);
@@ -475,7 +485,7 @@ io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage
return out;
}
io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage type,
io::sstream& CodeGenerator::generateSurfaceShaderInputs(io::sstream& out, ShaderStage stage,
const AttributeBitset& attributes, Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const {
auto const& attributeDatabase = MaterialBuilder::getAttributeDatabase();
@@ -488,7 +498,7 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t
generateDefine(out, attributeDatabase[i].getDefineName().c_str(), true);
});
if (type == ShaderStage::VERTEX) {
if (stage == ShaderStage::VERTEX) {
out << "\n";
attributes.forEachSetBit([&out, &attributeDatabase, this](size_t i) {
auto const& attribute = attributeDatabase[i];
@@ -507,16 +517,16 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t
}
out << "\n";
out << SHADERS_VARYINGS_GLSL_DATA;
out << SHADERS_SURFACE_VARYINGS_GLSL_DATA;
return out;
}
io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage type,
io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage stage,
const CString& name, size_t index,
MaterialBuilder::VariableQualifier qualifier,
MaterialBuilder::Precision precision,
MaterialBuilder::OutputType outputType) const {
if (name.empty() || type == ShaderStage::VERTEX) {
if (name.empty() || stage == ShaderStage::VERTEX) {
return out;
}
@@ -577,10 +587,10 @@ io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage type,
}
io::sstream& CodeGenerator::generateDepthShaderMain(io::sstream& out, ShaderStage type) {
assert(type != ShaderStage::VERTEX);
if (type == ShaderStage::FRAGMENT) {
out << SHADERS_DEPTH_MAIN_FS_DATA;
io::sstream& CodeGenerator::generateSurfaceDepthMain(io::sstream& out, ShaderStage stage) {
assert(stage != ShaderStage::VERTEX);
if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_DEPTH_MAIN_FS_DATA;
}
return out;
}
@@ -776,7 +786,7 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade
return out;
}
io::sstream& CodeGenerator::generateSamplers(utils::io::sstream& out,
io::sstream& CodeGenerator::generateCommonSamplers(utils::io::sstream& out,
filament::DescriptorSetBindingPoints set,
filament::SamplerInterfaceBlock::SamplerInfoList const& list) const {
if (list.empty()) {
@@ -825,7 +835,7 @@ io::sstream& CodeGenerator::generateSamplers(utils::io::sstream& out,
return out;
}
io::sstream& CodeGenerator::generateSubpass(io::sstream& out, SubpassInfo subpass) {
io::sstream& CodeGenerator::generatePostProcessSubpass(io::sstream& out, SubpassInfo subpass) {
if (!subpass.isValid) {
return out;
}
@@ -1013,21 +1023,19 @@ io::sstream& CodeGenerator::generateQualityDefine(io::sstream& out, ShaderQualit
return out;
}
io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderStage stage) {
io::sstream& CodeGenerator::generateSurfaceCommon(io::sstream& out, ShaderStage stage) {
out << SHADERS_COMMON_MATH_GLSL_DATA;
switch (stage) {
case ShaderStage::VERTEX:
out << SHADERS_COMMON_INSTANCING_GLSL_DATA;
out << SHADERS_COMMON_SHADOWING_GLSL_DATA;
out << SHADERS_SURFACE_INSTANCING_GLSL_DATA;
out << SHADERS_SURFACE_SHADOWING_GLSL_DATA;
break;
case ShaderStage::FRAGMENT:
out << SHADERS_COMMON_INSTANCING_GLSL_DATA;
out << SHADERS_COMMON_SHADOWING_GLSL_DATA;
out << SHADERS_SURFACE_INSTANCING_GLSL_DATA;
out << SHADERS_SURFACE_SHADOWING_GLSL_DATA;
out << SHADERS_COMMON_SHADING_FS_DATA;
out << SHADERS_COMMON_GRAPHICS_FS_DATA;
out << SHADERS_COMMON_MATERIAL_FS_DATA;
out << SHADERS_SURFACE_MATERIAL_FS_DATA;
break;
case ShaderStage::COMPUTE:
out << '\n';
@@ -1037,89 +1045,87 @@ io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderStage stage)
return out;
}
io::sstream& CodeGenerator::generatePostProcessCommon(io::sstream& out, ShaderStage type) {
io::sstream& CodeGenerator::generatePostProcessCommon(io::sstream& out, ShaderStage stage) {
out << SHADERS_COMMON_MATH_GLSL_DATA;
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
if (stage == ShaderStage::VERTEX) {
} else if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_COMMON_SHADING_FS_DATA;
out << SHADERS_COMMON_GRAPHICS_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateFog(io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_FOG_FS_DATA;
io::sstream& CodeGenerator::generateSurfaceFog(io::sstream& out, ShaderStage stage) {
if (stage == ShaderStage::VERTEX) {
} else if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_FOG_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateCommonMaterial(io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
out << SHADERS_MATERIAL_INPUTS_VS_DATA;
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_MATERIAL_INPUTS_FS_DATA;
io::sstream& CodeGenerator::generateSurfaceMaterial(io::sstream& out, ShaderStage stage) {
if (stage == ShaderStage::VERTEX) {
out << SHADERS_SURFACE_MATERIAL_INPUTS_VS_DATA;
} else if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_MATERIAL_INPUTS_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderStage stage) {
if (stage == ShaderStage::VERTEX) {
out << SHADERS_POST_PROCESS_INPUTS_VS_DATA;
} else if (type == ShaderStage::FRAGMENT) {
} else if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_POST_PROCESS_INPUTS_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generatePostProcessGetters(io::sstream& out, ShaderStage type) {
io::sstream& CodeGenerator::generatePostProcessGetters(io::sstream& out, ShaderStage stage) {
out << SHADERS_COMMON_GETTERS_GLSL_DATA;
if (type == ShaderStage::VERTEX) {
if (stage == ShaderStage::VERTEX) {
out << SHADERS_POST_PROCESS_GETTERS_VS_DATA;
} else if (type == ShaderStage::FRAGMENT) {
} else if (stage == ShaderStage::FRAGMENT) {
}
return out;
}
io::sstream& CodeGenerator::generateGetters(io::sstream& out, ShaderStage stage) {
io::sstream& CodeGenerator::generateSurfaceGetters(io::sstream& out, ShaderStage stage) {
out << SHADERS_COMMON_GETTERS_GLSL_DATA;
switch (stage) {
case ShaderStage::VERTEX:
out << SHADERS_GETTERS_VS_DATA;
out << SHADERS_SURFACE_GETTERS_VS_DATA;
break;
case ShaderStage::FRAGMENT:
out << SHADERS_GETTERS_FS_DATA;
out << SHADERS_SURFACE_GETTERS_FS_DATA;
break;
case ShaderStage::COMPUTE:
out << SHADERS_GETTERS_CS_DATA;
out << SHADERS_SURFACE_GETTERS_CS_DATA;
break;
}
return out;
}
io::sstream& CodeGenerator::generateParameters(io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_SHADING_PARAMETERS_FS_DATA;
io::sstream& CodeGenerator::generateSurfaceParameters(io::sstream& out, ShaderStage stage) {
if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_SHADING_PARAMETERS_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateShaderLit(io::sstream& out, ShaderStage type,
io::sstream& CodeGenerator::generateSurfaceLit(io::sstream& out, ShaderStage stage,
filament::Variant variant, Shading shading, bool customSurfaceShading) {
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_COMMON_LIGHTING_FS_DATA;
if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_LIGHTING_FS_DATA;
if (filament::Variant::isShadowReceiverVariant(variant)) {
out << SHADERS_SHADOWING_FS_DATA;
out << SHADERS_SURFACE_SHADOWING_FS_DATA;
}
// the only reason we have this assert here is that we used to have a check,
// which seemed unnecessary.
assert_invariant(shading != Shading::UNLIT);
out << SHADERS_BRDF_FS_DATA;
out << SHADERS_SURFACE_BRDF_FS_DATA;
switch (shading) {
case Shading::UNLIT:
// can't happen
@@ -1127,54 +1133,53 @@ io::sstream& CodeGenerator::generateShaderLit(io::sstream& out, ShaderStage type
case Shading::SPECULAR_GLOSSINESS:
case Shading::LIT:
if (customSurfaceShading) {
out << SHADERS_SHADING_LIT_CUSTOM_FS_DATA;
out << SHADERS_SURFACE_SHADING_LIT_CUSTOM_FS_DATA;
} else {
out << SHADERS_SHADING_MODEL_STANDARD_FS_DATA;
out << SHADERS_SURFACE_SHADING_MODEL_STANDARD_FS_DATA;
}
break;
case Shading::SUBSURFACE:
out << SHADERS_SHADING_MODEL_SUBSURFACE_FS_DATA;
out << SHADERS_SURFACE_SHADING_MODEL_SUBSURFACE_FS_DATA;
break;
case Shading::CLOTH:
out << SHADERS_SHADING_MODEL_CLOTH_FS_DATA;
out << SHADERS_SURFACE_SHADING_MODEL_CLOTH_FS_DATA;
break;
}
out << SHADERS_AMBIENT_OCCLUSION_FS_DATA;
out << SHADERS_LIGHT_INDIRECT_FS_DATA;
out << SHADERS_SURFACE_AMBIENT_OCCLUSION_FS_DATA;
out << SHADERS_SURFACE_LIGHT_INDIRECT_FS_DATA;
if (variant.hasDirectionalLighting()) {
out << SHADERS_LIGHT_DIRECTIONAL_FS_DATA;
out << SHADERS_SURFACE_LIGHT_DIRECTIONAL_FS_DATA;
}
if (variant.hasDynamicLighting()) {
out << SHADERS_LIGHT_PUNCTUAL_FS_DATA;
out << SHADERS_SURFACE_LIGHT_PUNCTUAL_FS_DATA;
}
out << SHADERS_SHADING_LIT_FS_DATA;
out << SHADERS_SURFACE_SHADING_LIT_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateShaderUnlit(io::sstream& out, ShaderStage type,
io::sstream& CodeGenerator::generateSurfaceUnlit(io::sstream& out, ShaderStage stage,
filament::Variant variant, bool hasShadowMultiplier) {
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
if (stage == ShaderStage::FRAGMENT) {
if (hasShadowMultiplier) {
if (filament::Variant::isShadowReceiverVariant(variant)) {
out << SHADERS_SHADOWING_FS_DATA;
out << SHADERS_SURFACE_SHADOWING_FS_DATA;
}
}
out << SHADERS_SHADING_UNLIT_FS_DATA;
out << SHADERS_SURFACE_SHADING_UNLIT_FS_DATA;
}
return out;
}
io::sstream& CodeGenerator::generateShaderReflections(utils::io::sstream& out, ShaderStage type) {
if (type == ShaderStage::VERTEX) {
} else if (type == ShaderStage::FRAGMENT) {
out << SHADERS_COMMON_LIGHTING_FS_DATA;
out << SHADERS_LIGHT_REFLECTIONS_FS_DATA;
out << SHADERS_SHADING_REFLECTIONS_FS_DATA;
io::sstream& CodeGenerator::generateSurfaceReflections(utils::io::sstream& out,
ShaderStage stage) {
if (stage == ShaderStage::FRAGMENT) {
out << SHADERS_SURFACE_LIGHTING_FS_DATA;
out << SHADERS_SURFACE_LIGHT_REFLECTIONS_FS_DATA;
out << SHADERS_SURFACE_SHADING_REFLECTIONS_FS_DATA;
}
return out;
}
+24 -24
View File
@@ -75,68 +75,68 @@ public:
static utils::io::sstream& generateSeparator(utils::io::sstream& out);
// generate prolog for the given shader
utils::io::sstream& generateProlog(utils::io::sstream& out, ShaderStage stage,
utils::io::sstream& generateCommonProlog(utils::io::sstream& out, ShaderStage stage,
MaterialInfo const& material, filament::Variant v) const;
static utils::io::sstream& generateEpilog(utils::io::sstream& out);
static utils::io::sstream& generateCommonEpilog(utils::io::sstream& out);
static utils::io::sstream& generateCommonTypes(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateSurfaceTypes(utils::io::sstream& out, ShaderStage stage);
// generate common functions for the given shader
static utils::io::sstream& generateCommon(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generatePostProcessCommon(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateCommonMaterial(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateSurfaceCommon(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generatePostProcessCommon(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateSurfaceMaterial(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateFog(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateSurfaceFog(utils::io::sstream& out, ShaderStage stage);
// generate the shader's main()
static utils::io::sstream& generateShaderMain(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generatePostProcessMain(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateSurfaceMain(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generatePostProcessMain(utils::io::sstream& out, ShaderStage stage);
// generate the shader's code for the lit shading model
static utils::io::sstream& generateShaderLit(utils::io::sstream& out, ShaderStage type,
static utils::io::sstream& generateSurfaceLit(utils::io::sstream& out, ShaderStage stage,
filament::Variant variant, filament::Shading shading, bool customSurfaceShading);
// generate the shader's code for the unlit shading model
static utils::io::sstream& generateShaderUnlit(utils::io::sstream& out, ShaderStage type,
static utils::io::sstream& generateSurfaceUnlit(utils::io::sstream& out, ShaderStage stage,
filament::Variant variant, bool hasShadowMultiplier);
// generate the shader's code for the screen-space reflections
static utils::io::sstream& generateShaderReflections(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateSurfaceReflections(utils::io::sstream& out, ShaderStage stage);
// generate declarations for custom interpolants
static utils::io::sstream& generateVariable(utils::io::sstream& out, ShaderStage stage,
static utils::io::sstream& generateCommonVariable(utils::io::sstream& out, ShaderStage stage,
const MaterialBuilder::CustomVariable& variable, size_t index);
// generate declarations for non-custom "in" variables
utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderStage type,
utils::io::sstream& generateSurfaceShaderInputs(utils::io::sstream& out, ShaderStage stage,
const filament::AttributeBitset& attributes, filament::Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const;
static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage stage);
// generate declarations for custom output variables
utils::io::sstream& generateOutput(utils::io::sstream& out, ShaderStage type,
utils::io::sstream& generateOutput(utils::io::sstream& out, ShaderStage stage,
const utils::CString& name, size_t index,
MaterialBuilder::VariableQualifier qualifier,
MaterialBuilder::Precision precision,
MaterialBuilder::OutputType outputType) const;
// generate no-op shader for depth prepass
static utils::io::sstream& generateDepthShaderMain(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateSurfaceDepthMain(utils::io::sstream& out, ShaderStage stage);
// generate samplers
utils::io::sstream& generateSamplers(utils::io::sstream& out,
utils::io::sstream& generateCommonSamplers(utils::io::sstream& out,
filament::DescriptorSetBindingPoints set,
filament::SamplerInterfaceBlock::SamplerInfoList const& list) const;
utils::io::sstream& generateSamplers(utils::io::sstream& out,
utils::io::sstream& generateCommonSamplers(utils::io::sstream& out,
filament::DescriptorSetBindingPoints set,
const filament::SamplerInterfaceBlock& sib) const {
return generateSamplers(out, set, sib.getSamplerInfoList());
return generateCommonSamplers(out, set, sib.getSamplerInfoList());
}
// generate subpass
static utils::io::sstream& generateSubpass(utils::io::sstream& out,
static utils::io::sstream& generatePostProcessSubpass(utils::io::sstream& out,
filament::SubpassInfo subpass);
// generate uniforms
@@ -174,9 +174,9 @@ public:
MaterialBuilder::PushConstantList const& pushConstants,
size_t const layoutLocation) const;
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateGetters(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateParameters(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateSurfaceGetters(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateSurfaceParameters(utils::io::sstream& out, ShaderStage stage);
static void fixupExternalSamplers(
std::string& shader, filament::SamplerInterfaceBlock const& sib,
+47 -48
View File
@@ -370,7 +370,7 @@ void ShaderGenerator::fixupExternalSamplers(ShaderModel sm, std::string& shader,
}
}
std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, const filament::Variant variant, Interpolation interpolation,
@@ -389,7 +389,7 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
const CodeGenerator cg(shaderModel, targetApi, targetLanguage, featureLevel);
cg.generateProlog(vs, ShaderStage::VERTEX, material, variant);
cg.generateCommonProlog(vs, ShaderStage::VERTEX, material, variant);
generateUserSpecConstants(cg, vs, mConstants);
@@ -436,15 +436,15 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::VERTEX;
});
cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation,
cg.generateSurfaceShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation,
vertexPushConstants);
CodeGenerator::generateCommonTypes(vs, ShaderStage::VERTEX);
CodeGenerator::generateSurfaceTypes(vs, ShaderStage::VERTEX);
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
CodeGenerator::generateVariable(vs, ShaderStage::VERTEX, variable, variableIndex++);
CodeGenerator::generateCommonVariable(vs, ShaderStage::VERTEX, variable, variableIndex++);
}
// materials defines
@@ -478,7 +478,7 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
DescriptorSetBindingPoints::PER_RENDERABLE,
+PerRenderableBindingPoints::MORPHING_UNIFORMS,
UibGenerator::getPerRenderableMorphingUib());
cg.generateSamplers(vs, DescriptorSetBindingPoints::PER_RENDERABLE,
cg.generateCommonSamplers(vs, DescriptorSetBindingPoints::PER_RENDERABLE,
SibGenerator::getPerRenderableSib(variant));
}
@@ -489,23 +489,23 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
CodeGenerator::generateSeparator(vs);
cg.generateSamplers(vs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
cg.generateCommonSamplers(vs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
// shader code
CodeGenerator::generateCommon(vs, ShaderStage::VERTEX);
CodeGenerator::generateGetters(vs, ShaderStage::VERTEX);
CodeGenerator::generateCommonMaterial(vs, ShaderStage::VERTEX);
CodeGenerator::generateSurfaceCommon(vs, ShaderStage::VERTEX);
CodeGenerator::generateSurfaceGetters(vs, ShaderStage::VERTEX);
CodeGenerator::generateSurfaceMaterial(vs, ShaderStage::VERTEX);
// main entry point
appendShader(vs, mMaterialVertexCode, mMaterialVertexLineOffset);
CodeGenerator::generateShaderMain(vs, ShaderStage::VERTEX);
CodeGenerator::generateSurfaceMain(vs, ShaderStage::VERTEX);
CodeGenerator::generateEpilog(vs);
CodeGenerator::generateCommonEpilog(vs);
return vs.c_str();
}
std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, const filament::Variant variant,
@@ -522,7 +522,7 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
const CodeGenerator cg(shaderModel, targetApi, targetLanguage, featureLevel);
io::sstream fs;
cg.generateProlog(fs, ShaderStage::FRAGMENT, material, variant);
cg.generateCommonProlog(fs, ShaderStage::FRAGMENT, material, variant);
generateUserSpecConstants(cg, fs, mConstants);
@@ -546,15 +546,15 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::FRAGMENT;
});
cg.generateShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
cg.generateSurfaceShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
fragmentPushConstants);
CodeGenerator::generateCommonTypes(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceTypes(fs, ShaderStage::FRAGMENT);
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
CodeGenerator::generateVariable(fs, ShaderStage::FRAGMENT, variable, variableIndex++);
CodeGenerator::generateCommonVariable(fs, ShaderStage::FRAGMENT, variable, variableIndex++);
}
// uniforms and samplers
@@ -626,21 +626,21 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
return pos == perViewDescriptorSetLayout.bindings.end();
}), list.end());
cg.generateSamplers(fs, DescriptorSetBindingPoints::PER_VIEW, list);
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_VIEW, list);
}
cg.generateSamplers(fs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
fs << "float filament_lodBias;\n";
// shading code
CodeGenerator::generateCommon(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateGetters(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateCommonMaterial(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateParameters(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceCommon(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceGetters(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceMaterial(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceParameters(fs, ShaderStage::FRAGMENT);
if (filament::Variant::isFogVariant(variant)) {
CodeGenerator::generateFog(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceFog(fs, ShaderStage::FRAGMENT);
}
// shading model
@@ -656,30 +656,30 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
}
// These variants are special and are treated as DEPTH variants. Filament will never
// request that variant for the color pass.
CodeGenerator::generateDepthShaderMain(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceDepthMain(fs, ShaderStage::FRAGMENT);
} else {
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
if (material.isLit) {
if (filament::Variant::isSSRVariant(variant)) {
CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceReflections(fs, ShaderStage::FRAGMENT);
} else {
CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant,
CodeGenerator::generateSurfaceLit(fs, ShaderStage::FRAGMENT, variant,
material.shading,material.hasCustomSurfaceShading);
}
} else {
CodeGenerator::generateShaderUnlit(fs, ShaderStage::FRAGMENT, variant,
CodeGenerator::generateSurfaceUnlit(fs, ShaderStage::FRAGMENT, variant,
material.hasShadowMultiplier);
}
// entry point
CodeGenerator::generateShaderMain(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateSurfaceMain(fs, ShaderStage::FRAGMENT);
}
CodeGenerator::generateEpilog(fs);
CodeGenerator::generateCommonEpilog(fs);
return fs.c_str();
}
std::string ShaderGenerator::createComputeProgram(filament::backend::ShaderModel shaderModel,
std::string ShaderGenerator::createSurfaceComputeProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material) const noexcept {
@@ -688,11 +688,11 @@ std::string ShaderGenerator::createComputeProgram(filament::backend::ShaderModel
const CodeGenerator cg(shaderModel, targetApi, targetLanguage, featureLevel);
io::sstream s;
cg.generateProlog(s, ShaderStage::COMPUTE, material, {});
cg.generateCommonProlog(s, ShaderStage::COMPUTE, material, {});
generateUserSpecConstants(cg, s, mConstants);
CodeGenerator::generateCommonTypes(s, ShaderStage::COMPUTE);
CodeGenerator::generateSurfaceTypes(s, ShaderStage::COMPUTE);
cg.generateUniforms(s, ShaderStage::COMPUTE,
DescriptorSetBindingPoints::PER_VIEW,
@@ -704,22 +704,21 @@ std::string ShaderGenerator::createComputeProgram(filament::backend::ShaderModel
+PerMaterialBindingPoints::MATERIAL_PARAMS,
material.uib);
cg.generateSamplers(s, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
cg.generateCommonSamplers(s, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
// generate SSBO
cg.generateBuffers(s, material.buffers);
// TODO: generate images
CodeGenerator::generateCommon(s, ShaderStage::COMPUTE);
CodeGenerator::generateGetters(s, ShaderStage::COMPUTE);
CodeGenerator::generateSurfaceCommon(s, ShaderStage::COMPUTE);
CodeGenerator::generateSurfaceGetters(s, ShaderStage::COMPUTE);
appendShader(s, mMaterialFragmentCode, mMaterialLineOffset);
CodeGenerator::generateShaderMain(s, ShaderStage::COMPUTE);
CodeGenerator::generateSurfaceMain(s, ShaderStage::COMPUTE);
CodeGenerator::generateEpilog(s);
CodeGenerator::generateCommonEpilog(s);
return s.c_str();
}
@@ -729,7 +728,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
MaterialInfo const& material, const filament::Variant::type_t variantKey) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage, featureLevel);
io::sstream vs;
cg.generateProlog(vs, ShaderStage::VERTEX, material, {});
cg.generateCommonProlog(vs, ShaderStage::VERTEX, material, {});
generateUserSpecConstants(cg, vs, mConstants);
@@ -738,7 +737,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
CodeGenerator::generateVariable(vs, ShaderStage::VERTEX, variable, variableIndex++);
CodeGenerator::generateCommonVariable(vs, ShaderStage::VERTEX, variable, variableIndex++);
}
CodeGenerator::generatePostProcessInputs(vs, ShaderStage::VERTEX);
@@ -754,7 +753,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
+PerMaterialBindingPoints::MATERIAL_PARAMS,
material.uib);
cg.generateSamplers(vs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
cg.generateCommonSamplers(vs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
CodeGenerator::generatePostProcessCommon(vs, ShaderStage::VERTEX);
CodeGenerator::generatePostProcessGetters(vs, ShaderStage::VERTEX);
@@ -763,7 +762,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
CodeGenerator::generatePostProcessMain(vs, ShaderStage::VERTEX);
CodeGenerator::generateEpilog(vs);
CodeGenerator::generateCommonEpilog(vs);
return vs.c_str();
}
@@ -773,7 +772,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
MaterialInfo const& material, uint8_t variant) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage, featureLevel);
io::sstream fs;
cg.generateProlog(fs, ShaderStage::FRAGMENT, material, {});
cg.generateCommonProlog(fs, ShaderStage::FRAGMENT, material, {});
generateUserSpecConstants(cg, fs, mConstants);
@@ -782,7 +781,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
CodeGenerator::generateVariable(fs, ShaderStage::FRAGMENT, variable, variableIndex++);
CodeGenerator::generateCommonVariable(fs, ShaderStage::FRAGMENT, variable, variableIndex++);
}
cg.generateUniforms(fs, ShaderStage::FRAGMENT,
@@ -795,10 +794,10 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
+PerMaterialBindingPoints::MATERIAL_PARAMS,
material.uib);
cg.generateSamplers(fs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
// subpass
CodeGenerator::generateSubpass(fs, material.subpass);
CodeGenerator::generatePostProcessSubpass(fs, material.subpass);
CodeGenerator::generatePostProcessCommon(fs, ShaderStage::FRAGMENT);
CodeGenerator::generatePostProcessGetters(fs, ShaderStage::FRAGMENT);
@@ -819,7 +818,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
CodeGenerator::generatePostProcessMain(fs, ShaderStage::FRAGMENT);
CodeGenerator::generateEpilog(fs);
CodeGenerator::generateCommonEpilog(fs);
return fs.c_str();
}
+3 -3
View File
@@ -58,21 +58,21 @@ public:
size_t vertexLineOffset,
MaterialBuilder::MaterialDomain materialDomain) noexcept;
std::string createVertexProgram(filament::backend::ShaderModel shaderModel,
std::string createSurfaceVertexProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, filament::Variant variant,
filament::Interpolation interpolation,
filament::VertexDomain vertexDomain) const noexcept;
std::string createFragmentProgram(filament::backend::ShaderModel shaderModel,
std::string createSurfaceFragmentProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, filament::Variant variant,
filament::Interpolation interpolation,
filament::UserVariantFilterMask variantFilter) const noexcept;
std::string createComputeProgram(filament::backend::ShaderModel shaderModel,
std::string createSurfaceComputeProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material) const noexcept;
@@ -56,6 +56,8 @@ public:
explicit MeshAssimp(filament::Engine& engine);
~MeshAssimp();
// This function takes over the ownership of `materials` to prevent crashes due to the
// incorrect order of resource destruction.
void addFromFile(const utils::Path& path,
std::map<std::string, filament::MaterialInstance*>& materials,
bool overrideMaterial = false);
@@ -127,8 +129,9 @@ private:
filament::Material* mDefaultColorMaterial = nullptr;
filament::Material* mDefaultTransparentColorMaterial = nullptr;
mutable std::unordered_map<uint64_t, filament::Material*> mGltfMaterialCache;
std::map<std::string, filament::MaterialInstance*> mMaterialInstances;
filament::Texture* mDefaultMap = nullptr;
filament::Texture* mDefaultNormalMap = nullptr;
float mDefaultMetallic = 0.0f;
@@ -138,8 +141,6 @@ private:
std::vector<utils::Entity> mRenderables;
std::vector<filament::Texture*> mTextures;
};
#endif // TNT_FILAMENT_SAMPLE_MESH_ASSIMP_H
+12 -9
View File
@@ -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;

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