Compare commits

..
Author SHA1 Message Date
Powei Feng d064e2ed78 test: single simple program 2025-02-13 17:49:31 +00:00
Grant Commodore a22873bb2e vk: extension support in shared context (#8415) 2025-02-11 14:04:24 -08:00
Ben Doherty b2801d0a5c Support including PlatformMetal.h in C++ headers (#8431) 2025-02-11 10:11:11 -08:00
Powei Feng 1a5f1cc6ab matdbg: fix three bugs (#8430)
1. changes weren't refreshed for windows/linux-mesa vulkan. This
   is due to a reordering of the shaders when the shader source
   is replaced. We fix this by ensuring the ordering before
   writing out the edit.
   Fixes #7286

2. A condition was flipped in the SourceFormatter causing the
   format feature to not work on linux

3. The material update status wasn't really propagated to the
   front-end due to not updating the status counter.
2025-02-11 07:50:45 +00:00
Powei Feng 9f5001d347 vk: fix debug code (#8429)
Some debug code that are only enabled for debug purposes have
not been properly refactored after the fvkutils commit.
2025-02-11 07:37:04 +00:00
Grant Commodore 9042f628d4 vk: Adds the layercount to the VulkanTexture and SwapChainBundle (#8392) 2025-02-10 17:50:45 -08:00
Sungun Park 83d71d0f57 Release Filament 1.57.0 2025-02-10 23:33:15 +00:00
Benjamin Doherty cb8b1bfefa Bump MATERIAL_VERSION to 57 2025-02-10 15:23:37 -08:00
Sungun Park 8824f59051 Move OpenGLDriverBase.h under src/opengl/ (#8433) 2025-02-10 15:21:02 -08:00
Benjamin Doherty d8af04f08f Add missing setDithering to jsbindings 2025-02-10 09:37:13 -08:00
Mathias Agopian 559bc4eb96 fix some missing includes and trivial warnings (#8414) 2025-02-07 14:48:37 -08:00
GavinKG c16cab239d Use CAMetalLayer to create MVK surfaces to avoid potential deadlocks. 2025-02-07 12:39:24 -08:00
wangjinhan 68719f913a Rename clearEntities to removeAllEntities and add noexcept. 2025-02-07 11:37:14 -08:00
wangjinhan 038ed69a92 Add clearEntities API in Scene.
The API works for Scene to clear all entities.
2025-02-07 11:37:14 -08:00
Mathias Agopian 69822a91cf the shadow passes get their own face culling mode
the new MaterialInstance::setCullingMode(color, shadow) API allows to
set a separate face culling mode for the color pass and the shadow 
passes.

FIXES[391679058]
2025-02-07 11:36:48 -08:00
Powei Feng 24ff10b5db vk: fix rendering to 2D view of 3D image (#8421)
FIXES=389760706
2025-02-07 16:32:25 +00:00
Sungun Park ec2f5b8078 Promote getEyeIndex() as a common helper (#8418)
Now the helper function `getEyeIndex` becomes available for all shader
stages including post-processing. It used to be only accessible from
surface vertex shaders.
2025-02-06 22:41:30 +00:00
Powei Feng 538aa39127 Release Filament 1.56.8 2025-02-06 11:13:56 -08:00
Powei Feng 8de56a2bbc Add ostream operator for ExternalImageHandle (#8416)
Without it, DEBUG_COMMAND_STREAM does not compile.
2025-02-05 23:52:05 +00:00
Mathias Agopian ea5d7d4f47 Add a way to retrieve the GL_RENDERER and GL_VENDOR strings
The API works this way:

```
auto vendor = OpenGLPlatform::getVendorString(engine->getDriver());
```

Obviously the Backend must be `Backend::OPENGL` and the `Driver` must 
have been created with an `OpenGLPlatform` subclass.


FIXES=[385367277]
2025-02-05 15:31:39 -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
188 changed files with 2988 additions and 1613 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)
+2
View File
@@ -7,3 +7,5 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Support including PlatformMetal.h in C++ files.
+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.57.0'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.56.8'
pod 'Filament', '~> 1.57.0'
```
## Documentation
+8
View File
@@ -7,6 +7,14 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.57.1
## v1.57.0
- matdbg: Add support for debugging ESSL 1.0 shaders
- backend: New platform API to better handle external textures [⚠️ **New Material Version**]
## v1.56.8
@@ -329,6 +329,18 @@ Java_com_google_android_filament_MaterialInstance_nSetCullingMode(JNIEnv*,
instance->setCullingMode((MaterialInstance::CullingMode) cullingMode);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetCullingModeSeparate(JNIEnv*, jclass,
jlong nativeMaterialInstance,
jlong colorPassCullingMode, jlong shadowPassCullingMode) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
instance->setCullingMode(
(MaterialInstance::CullingMode) colorPassCullingMode,
(MaterialInstance::CullingMode) shadowPassCullingMode);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetColorWrite(JNIEnv*,
@@ -505,6 +517,14 @@ Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, j
return (jint)instance->getCullingMode();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_MaterialInstance_nGetShadowCullingMode(JNIEnv* env, jclass,
jlong nativeMaterialInstance) {
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return (jint)instance->getShadowCullingMode();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
@@ -556,6 +556,20 @@ public class MaterialInstance {
nSetCullingMode(getNativeObject(), mode.ordinal());
}
/**
* Overrides the default triangle culling state that was set on the material separately for the
* color and shadow passes
*
* @see
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
* Rasterization: culling</a>
*/
public void setCullingMode(@NonNull Material.CullingMode colorPassCullingMode,
@NonNull Material.CullingMode shadowPassCullingMode) {
nSetCullingModeSeparate(getNativeObject(),
colorPassCullingMode.ordinal(), shadowPassCullingMode.ordinal());
}
/**
* Returns the face culling mode.
*/
@@ -564,6 +578,14 @@ public class MaterialInstance {
return sCullingModeValues[nGetCullingMode(getNativeObject())];
}
/**
* Returns the face culling mode for the shadow passes.
*/
@NonNull
public Material.CullingMode getShadowCullingMode() {
return sCullingModeValues[nGetShadowCullingMode(getNativeObject())];
}
/**
* Overrides the default color-buffer write state that was set on the material.
*
@@ -920,6 +942,8 @@ public class MaterialInstance {
private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided);
private static native void nSetCullingMode(long nativeMaterialInstance, long mode);
private static native void nSetCullingModeSeparate(long nativeMaterialInstance,
long colorPassCullingMode, long shadowPassCullingMode);
private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable);
private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable);
private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable);
@@ -952,6 +976,7 @@ public class MaterialInstance {
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
private static native int nGetCullingMode(long nativeMaterialInstance);
private static native int nGetShadowCullingMode(long nativeMaterialInstance);
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.56.8
VERSION_NAME=1.57.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
-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,
+47 -1
View File
@@ -25,6 +25,8 @@
#include <stddef.h>
#include <stdint.h>
#include <atomic>
namespace filament::backend {
class Driver;
@@ -41,6 +43,50 @@ 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;
private:
friend utils::io::ostream& operator<<(utils::io::ostream& out,
ExternalImageHandle const& handle);
};
using ExternalImageHandleRef = ExternalImageHandle const&;
/**
* The type of technique for stereoscopic rendering. (Note that the materials used will need to
* be compatible with the chosen technique.)
@@ -123,7 +169,7 @@ public:
*
* @return nullptr on failure, or a pointer to the newly created driver.
*/
virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
const DriverConfig& driverConfig) noexcept = 0;
/**
@@ -23,6 +23,7 @@
#include <utils/compiler.h>
#include <utils/Invocable.h>
#include <utils/CString.h>
#include <stddef.h>
#include <stdint.h>
@@ -51,12 +52,23 @@ 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
};
/**
* Return the OpenGL vendor string of the specified Driver instance.
* @return The GL_VENDOR string
*/
static utils::CString getVendorString(Driver const* UTILS_NONNULL driver);
/**
* Return the OpenGL vendor string of the specified Driver instance
* @return The GL_RENDERER string
*/
static utils::CString getRendererString(Driver const* UTILS_NONNULL driver);
/**
* Called by the driver to destroy the OpenGL context. This should clean up any windows
* or buffers from initialization. This is for instance where `eglDestroyContext` would be
@@ -324,36 +336,45 @@ 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.
@@ -17,7 +17,6 @@
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
#include <backend/DriverEnums.h>
#include <backend/platforms/OpenGLPlatform.h>
#include <stdint.h>
@@ -34,12 +33,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 +60,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
@@ -75,8 +80,7 @@ protected:
* Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation
* that supports OpenGL/OpenGL ES.
*/
Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override;
/**
* This returns zero. This method can be overridden to return something more useful.
@@ -118,9 +122,10 @@ 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 +193,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,
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
#define TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
#import <Metal/Metal.h>
namespace filament::backend {
struct MetalDevice {
id<MTLDevice> device;
};
struct MetalCommandQueue {
id<MTLCommandQueue> commandQueue;
};
struct MetalCommandBuffer {
id<MTLCommandBuffer> commandBuffer;
};
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
@@ -20,12 +20,17 @@
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
#import <Metal/Metal.h>
namespace filament::backend {
struct PlatformMetalImpl;
// In order for this header to be compatible with Objective-C and C++, we use these wrappers around
// id<MTL*> objects.
// See PlatformMetal-Objc.h.
struct MetalDevice;
struct MetalCommandQueue;
struct MetalCommandBuffer;
class PlatformMetal final : public Platform {
public:
PlatformMetal();
@@ -41,21 +46,22 @@ public:
* free to decide which one to use. On mobile systems with a single GPU, implementations should
* simply return the result of MTLCreateSystemDefaultDevice();
*/
virtual id<MTLDevice> createDevice() noexcept;
virtual void createDevice(MetalDevice& outDevice) noexcept;
/**
* Create a command submission queue on the Metal device object.
*
* @param device The device which was returned from createDevice()
*/
virtual id<MTLCommandQueue> createCommandQueue(id<MTLDevice> device) noexcept;
virtual void createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept;
/**
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
* guaranteed to execute before all subsequent command buffers created either by Filament, or
* further calls to this method.
*/
id<MTLCommandBuffer> createAndEnqueueCommandBuffer() noexcept;
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
/**
* The action to take if a Drawable cannot be acquired.
@@ -71,6 +71,9 @@ public:
// where the gpu only has one graphics queue. Then the client needs to ensure that no
// concurrent access can occur.
uint32_t graphicsQueueIndex = 0xFFFFFFFF;
bool debugUtilsSupported = false;
bool debugMarkersSupported = false;
bool multiviewSupported = false;
};
/**
@@ -88,6 +91,7 @@ public:
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
uint32_t layerCount = 1;
bool isProtected = false;
};
@@ -303,6 +307,11 @@ public:
*/
uint32_t height;
/**
* The layerCount of the external image
*/
uint32_t layerCount;
/**
* The layer count of the external image
*/
@@ -50,7 +50,7 @@
#include <stdint.h>
// Set to true to print every command out on log.d. This requires RTTI and DEBUG
#define DEBUG_COMMAND_STREAM false
#define DEBUG_COMMAND_STREAM true
namespace filament::backend {
@@ -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;
};
+94
View File
@@ -16,8 +16,102 @@
#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;
}
utils::io::ostream& operator<<(utils::io::ostream& out,
Platform::ExternalImageHandle const& handle) {
out << "ExternalImageHandle{" << handle.mTarget << "}";
return out;
}
// --------------------------------------------------------------------------------------------------------------------
Platform::ExternalImage::~ExternalImage() noexcept = default;
// --------------------------------------------------------------------------------------------------------------------
Platform::Platform() noexcept = default;
// this generates the vtable in this translation unit
+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;
+33 -4
View File
@@ -31,6 +31,7 @@
#include "MetalTimerQuery.h"
#include <backend/platforms/PlatformMetal.h>
#include <backend/platforms/PlatformMetal-ObjC.h>
#include <CoreVideo/CVMetalTexture.h>
#include <CoreVideo/CVPixelBuffer.h>
@@ -120,7 +121,10 @@ MetalDriver::MetalDriver(
TrackedMetalBuffer::setPlatform(platform);
ScopedAllocationTimer::setPlatform(platform);
mContext->device = mPlatform.createDevice();
MetalDevice device;
device.device = nil;
mPlatform.createDevice(device);
mContext->device = device.device;
assert_invariant(mContext->device);
mContext->emptyBuffer = [mContext->device newBufferWithLength:16
@@ -186,7 +190,12 @@ MetalDriver::MetalDriver(
[mContext->device.name containsString:@"Apple A8 GPU"] ||
[mContext->device.name containsString:@"Apple A7 GPU"];
mContext->commandQueue = mPlatform.createCommandQueue(mContext->device);
MetalCommandQueue commandQueue;
commandQueue.commandQueue = nil;
mPlatform.createCommandQueue(device, commandQueue);
assert_invariant(commandQueue.commandQueue);
mContext->commandQueue = commandQueue.commandQueue;
mContext->pipelineStateCache.setDevice(mContext->device);
mContext->depthStencilStateCache.setDevice(mContext->device);
mContext->samplerStateCache.setDevice(mContext->device);
@@ -513,6 +522,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 +764,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 +968,10 @@ ShaderModel MetalDriver::getShaderModel() const noexcept {
#endif
}
ShaderLanguage MetalDriver::getShaderLanguage() const noexcept {
return ShaderLanguage::MSL;
}
Handle<HwStream> MetalDriver::createStreamNative(void* stream) {
return {};
}
@@ -1135,8 +1160,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 +1239,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
+9 -7
View File
@@ -15,6 +15,7 @@
*/
#include <backend/platforms/PlatformMetal.h>
#include <backend/platforms/PlatformMetal-ObjC.h>
#include "MetalDriverFactory.h"
@@ -47,7 +48,7 @@ Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::Dri
return MetalDriverFactory::create(this, driverConfig);
}
id<MTLDevice> PlatformMetal::createDevice() noexcept {
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
id<MTLDevice> result;
#if !defined(FILAMENT_IOS)
@@ -72,19 +73,20 @@ id<MTLDevice> PlatformMetal::createDevice() noexcept {
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
return result;
outDevice.device = result;
}
id<MTLCommandQueue> PlatformMetal::createCommandQueue(id<MTLDevice> device) noexcept {
pImpl->mCommandQueue = [device newCommandQueue];
void PlatformMetal::createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
pImpl->mCommandQueue = [device.device newCommandQueue];
pImpl->mCommandQueue.label = @"Filament";
return pImpl->mCommandQueue;
outCommandQueue.commandQueue = pImpl->mCommandQueue;
}
id<MTLCommandBuffer> PlatformMetal::createAndEnqueueCommandBuffer() noexcept {
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
[commandBuffer enqueue];
return commandBuffer;
outCommandBuffer.commandBuffer = commandBuffer;
}
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
+14
View File
@@ -14,9 +14,16 @@
* limitations under the License.
*/
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include "noop/NoopDriver.h"
#include "CommandStreamDispatcher.h"
#include <backend/Handle.h>
#include <stdint.h>
namespace filament::backend {
Driver* NoopDriver::create() {
@@ -39,6 +46,10 @@ ShaderModel NoopDriver::getShaderModel() const noexcept {
#endif
}
ShaderLanguage NoopDriver::getShaderLanguage() const noexcept {
return ShaderLanguage::ESSL3;
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<NoopDriver>;
@@ -258,6 +269,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 };
+124 -64
View File
@@ -39,6 +39,7 @@
#include <backend/Program.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/CommandStream.h"
#include "private/backend/Dispatcher.h"
#include "private/backend/DriverApi.h"
@@ -46,9 +47,11 @@
#include <utils/BitmaskEnum.h>
#include <utils/FixedCapacityVector.h>
#include <utils/CString.h>
#include <utils/Invocable.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/Systrace.h>
#include <utils/Slice.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
@@ -75,9 +78,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
@@ -152,8 +157,8 @@ using namespace GLUtils;
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
assert_invariant(platform);
OpenGLPlatform* const ec = platform;
@@ -220,7 +225,7 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
}
#endif
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig validConfig{ driverConfig };
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
@@ -275,7 +280,6 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
driverConfig.disableHandleUseAfterFreeCheck),
mDriverConfig(driverConfig),
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
// set a reasonable default value for our stream array
mTexturesWithStreamsAttached.reserve(8);
mStreamsWithPendingAcquiredImage.reserve(8);
@@ -349,6 +353,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
// ------------------------------------------------------------------------------------------------
@@ -360,8 +368,8 @@ void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
mContext.bindSampler(unit, sampler);
}
void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
void OpenGLDriver::setPushConstant(ShaderStage stage, uint8_t index,
PushConstantVariant value) {
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
#if FILAMENT_ENABLE_MATDBG
@@ -370,7 +378,7 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
}
#endif
utils::Slice<std::pair<GLint, ConstantType>> constants;
Slice<std::pair<GLint, ConstantType>> constants;
if (stage == ShaderStage::VERTEX) {
constants = mCurrentPushConstants->vertexConstants;
} else if (stage == ShaderStage::FRAGMENT) {
@@ -576,6 +584,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>();
}
@@ -671,7 +683,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
bo->gl.buffer = malloc(byteCount);
memset(bo->gl.buffer, 0, byteCount);
} else {
bo->gl.binding = GLUtils::getBufferBindingType(bindingType);
bo->gl.binding = getBufferBindingType(bindingType);
glGenBuffers(1, &bo->gl.id);
gl.bindBuffer(bo->gl.binding, bo->gl.id);
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
@@ -748,7 +760,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
}
UTILS_NOINLINE
void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
void OpenGLDriver::textureStorage(GLTexture* t,
uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept {
auto& gl = mContext;
@@ -897,25 +909,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 +983,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 +1045,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 +1117,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
@@ -1092,7 +1146,7 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
}
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
void* image, uint32_t plane) {
// not relevant for the OpenGL backend
}
@@ -1408,7 +1462,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
&& ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0)
|| gl.ext.EXT_multisampled_render_to_texture2)) {
assert_invariant(rt->gl.samples > 1);
// We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture,
// We have a multi-sample rendertarget, and we have EXT_multisampled_render_to_texture,
// so, we can directly use a 1-sample texture as attachment, multi-sample resolve,
// will happen automagically and efficiently in the driver.
// This extension only exists on OpenGL ES.
@@ -1608,9 +1662,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
rt->gl.samples = samples;
rt->targets = targets;
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = { std::numeric_limits<uint32_t>::max() };
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = { 0 };
auto checkDimensions = [&tmin, &tmax](GLTexture* t, uint8_t level) {
UTILS_UNUSED_IN_RELEASE vec2<uint32_t> tmin = { std::numeric_limits<uint32_t>::max() };
UTILS_UNUSED_IN_RELEASE vec2<uint32_t> tmax = { 0 };
auto checkDimensions = [&tmin, &tmax](GLTexture const* t, uint8_t level) {
const auto twidth = std::max(1u, t->width >> level);
const auto theight = std::max(1u, t->height >> level);
tmin = { std::min(tmin.x, twidth), std::min(tmin.y, theight) };
@@ -1864,7 +1918,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);
}
@@ -2312,11 +2366,11 @@ bool OpenGLDriver::isStereoSupported() {
return false;
}
switch (mDriverConfig.stereoscopicType) {
case backend::StereoscopicType::INSTANCED:
case StereoscopicType::INSTANCED:
return mContext.ext.EXT_clip_cull_distance;
case backend::StereoscopicType::MULTIVIEW:
case StereoscopicType::MULTIVIEW:
return mContext.ext.OVR_multiview2;
case backend::StereoscopicType::NONE:
case StereoscopicType::NONE:
return false;
}
}
@@ -2329,7 +2383,7 @@ bool OpenGLDriver::isDepthStencilResolveSupported() {
return true;
}
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat format) {
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat) {
return true;
}
@@ -2363,12 +2417,12 @@ FeatureLevel OpenGLDriver::getFeatureLevel() {
return mContext.getFeatureLevel();
}
math::float2 OpenGLDriver::getClipSpaceParams() {
float2 OpenGLDriver::getClipSpaceParams() {
return mContext.ext.EXT_clip_control ?
// z-coordinate of virtual and physical clip-space is in [-w, 0]
math::float2{ 1.0f, 0.0f } :
float2{ 1.0f, 0.0f } :
// z-coordinate of virtual clip-space is in [-w,0], physical is in [-w, w]
math::float2{ 2.0f, -1.0f };
float2{ 2.0f, -1.0f };
}
uint8_t OpenGLDriver::getMaxDrawBuffers() {
@@ -2432,7 +2486,7 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
@@ -2608,7 +2662,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p) {
@@ -2717,7 +2771,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p) {
@@ -2803,6 +2857,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);
}
@@ -3354,8 +3412,8 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
#endif
}
void OpenGLDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
uint32_t offset, uint32_t size, BufferDescriptor&& p) {
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
assert_invariant(!gl.isES2());
@@ -3502,13 +3560,13 @@ void OpenGLDriver::beginFrame(
}
}
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
FrameScheduledCallback&& callback, uint64_t flags) {
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain>, CallbackHandler*,
FrameScheduledCallback&& /*callback*/, uint64_t /*flags*/) {
DEBUG_MARKER()
}
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain>,
CallbackHandler*, Invocable<void()>&& /*callback*/) {
DEBUG_MARKER()
}
@@ -3539,9 +3597,9 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
}
void OpenGLDriver::updateDescriptorSetBuffer(
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::BufferObjectHandle boh,
DescriptorSetHandle dsh,
descriptor_binding_t binding,
BufferObjectHandle boh,
uint32_t offset, uint32_t size) {
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
GLBufferObject* bo = boh ? handle_cast<GLBufferObject*>(boh) : nullptr;
@@ -3549,9 +3607,9 @@ void OpenGLDriver::updateDescriptorSetBuffer(
}
void OpenGLDriver::updateDescriptorSetTexture(
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::TextureHandle th,
DescriptorSetHandle dsh,
descriptor_binding_t binding,
TextureHandle th,
SamplerParams params) {
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
GLTexture* t = th ? handle_cast<GLTexture*>(th) : nullptr;
@@ -3584,7 +3642,7 @@ void OpenGLDriver::finish(int) {
UTILS_NOINLINE
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
mContext.colorMask(GL_TRUE);
@@ -3907,9 +3965,9 @@ void OpenGLDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
}
void OpenGLDriver::bindDescriptorSet(
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
backend::DescriptorSetOffsetArray&& offsets) {
DescriptorSetHandle dsh,
descriptor_set_t set,
DescriptorSetOffsetArray&& offsets) {
if (UTILS_UNLIKELY(!dsh)) {
mBoundDescriptorSets[set].dsh = dsh;
@@ -3941,7 +3999,7 @@ void OpenGLDriver::bindDescriptorSet(
}
}
void OpenGLDriver::updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept {
void OpenGLDriver::updateDescriptors(bitset8 invalidDescriptorSets) noexcept {
assert_invariant(mBoundProgram);
auto const offsetOnly = mInvalidDescriptorSetBindingOffsets & ~mInvalidDescriptorSetBindings;
invalidDescriptorSets.forEachSetBit([this, offsetOnly,
@@ -4053,7 +4111,7 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph,
}
}
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 workGroupCount) {
DEBUG_MARKER()
getShaderCompilerService().tick();
@@ -4090,4 +4148,6 @@ template class ConcreteDispatcher<OpenGLDriver>;
} // namespace filament::backend
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
+30 -20
View File
@@ -19,6 +19,7 @@
#include "DriverBase.h"
#include "OpenGLContext.h"
#include "OpenGLDriverBase.h"
#include "OpenGLTimerQuery.h"
#include "GLBufferObject.h"
#include "GLDescriptorSet.h"
@@ -26,11 +27,10 @@
#include "GLTexture.h"
#include "ShaderCompilerService.h"
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/AcquiredImage.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/Platform.h>
#include <backend/Program.h>
#include <backend/TargetBufferInfo.h>
@@ -41,6 +41,7 @@
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <math/vec4.h>
@@ -74,14 +75,14 @@ class OpenGLProgram;
class TimerQueryFactoryInterface;
struct PushConstantBundle;
class OpenGLDriver final : public DriverBase {
class OpenGLDriver final : public OpenGLDriverBase {
inline explicit OpenGLDriver(OpenGLPlatform* platform,
const Platform::DriverConfig& driverConfig) noexcept;
~OpenGLDriver() noexcept final;
Dispatcher getDispatcher() const noexcept final;
~OpenGLDriver() noexcept override;
Dispatcher getDispatcher() const noexcept override;
public:
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext,
static OpenGLDriver* create(OpenGLPlatform* platform, void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept;
class DebugMarker {
@@ -184,7 +185,7 @@ public:
std::condition_variable cond;
FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED };
};
std::shared_ptr<State> state{ std::make_shared<GLFence::State>() };
std::shared_ptr<State> state{ std::make_shared<State>() };
};
OpenGLDriver(OpenGLDriver const&) = delete;
@@ -203,12 +204,21 @@ private:
return mShaderCompilerService;
}
ShaderModel getShaderModel() const noexcept final;
ShaderModel getShaderModel() const noexcept override;
ShaderLanguage getShaderLanguage() const noexcept override;
/*
* Driver interface
* OpenGLDriver interface
*/
utils::CString getVendorString() const noexcept override {
return utils::CString{ mContext.state.vendor };
}
utils::CString getRendererString() const noexcept override {
return utils::CString{ mContext.state.renderer };
}
template<typename T>
friend class ConcreteDispatcher;
@@ -235,21 +245,21 @@ private:
}
template<typename D, typename B, typename ... ARGS>
typename std::enable_if<std::is_base_of<B, D>::value, D>::type*
std::enable_if_t<std::is_base_of_v<B, D>, D>*
construct(Handle<B> const& handle, ARGS&& ... args) {
return mHandleAllocator.destroyAndConstruct<D, B>(handle, std::forward<ARGS>(args) ...);
}
template<typename B, typename D,
typename = typename std::enable_if<std::is_base_of<B, D>::value, D>::type>
typename = std::enable_if_t<std::is_base_of_v<B, D>, D>>
void destruct(Handle<B>& handle, D const* p) noexcept {
return mHandleAllocator.deallocate(handle, p);
}
template<typename Dp, typename B>
typename std::enable_if_t<
std::enable_if_t<
std::is_pointer_v<Dp> &&
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
handle_cast(Handle<B>& handle) {
return mHandleAllocator.handle_cast<Dp, B>(handle);
}
@@ -260,9 +270,9 @@ private:
}
template<typename Dp, typename B>
inline typename std::enable_if_t<
std::enable_if_t<
std::is_pointer_v<Dp> &&
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
handle_cast(Handle<B> const& handle) {
return mHandleAllocator.handle_cast<Dp, B>(handle);
}
@@ -287,13 +297,13 @@ private:
void setStencilState(StencilState ss) noexcept;
void setTextureData(GLTexture* t,
void setTextureData(GLTexture const* t,
uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p);
void setCompressedTextureData(GLTexture* t,
void setCompressedTextureData(GLTexture const* t,
uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
@@ -302,7 +312,7 @@ private:
void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width,
uint32_t height, uint8_t samples) const noexcept;
void textureStorage(OpenGLDriver::GLTexture* t, uint32_t width, uint32_t height,
void textureStorage(GLTexture* t, uint32_t width, uint32_t height,
uint32_t depth, bool useProtectedMemory) noexcept;
/* State tracking GL wrappers... */
@@ -334,9 +344,9 @@ private:
void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept;
struct {
backend::DescriptorSetHandle dsh;
DescriptorSetHandle dsh;
std::array<uint32_t, CONFIG_UNIFORM_BINDING_COUNT> offsets;
} mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT];
} mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT] = {};
void clearWithRasterPipe(TargetBufferFlags clearFlags,
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept;
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
#include "DriverBase.h"
#include <utils/CString.h>
namespace filament::backend {
class OpenGLDriverBase : public DriverBase {
protected:
~OpenGLDriverBase() override;
public:
virtual utils::CString getVendorString() const noexcept = 0;
virtual utils::CString getRendererString() const noexcept = 0;
};
} // filament::backend
#endif //TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
+38 -3
View File
@@ -16,6 +16,7 @@
#include <backend/platforms/OpenGLPlatform.h>
#include "OpenGLDriverBase.h"
#include "OpenGLDriverFactory.h"
#include <backend/AcquiredImage.h>
@@ -23,21 +24,45 @@
#include <backend/Platform.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <utils/CString.h>
#include <utils/Invocable.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "OpenGLDriver.h"
namespace filament::backend {
OpenGLDriverBase::~OpenGLDriverBase() = default;
Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform,
void* sharedContext, const Platform::DriverConfig& driverConfig) {
void* sharedContext, const DriverConfig& driverConfig) {
return OpenGLDriverFactory::create(platform, sharedContext, driverConfig);
}
OpenGLPlatform::~OpenGLPlatform() noexcept = default;
utils::CString OpenGLPlatform::getVendorString(Driver const* driver) {
auto const p = static_cast<OpenGLDriverBase const*>(driver);
#if UTILS_HAS_RTTI
FILAMENT_CHECK_POSTCONDITION(dynamic_cast<OpenGLDriverBase const*>(driver))
<< "Driver* has not been allocated with OpenGLPlatform";
#endif
return p->getVendorString();
}
utils::CString OpenGLPlatform::getRendererString(Driver const* driver) {
auto const p = static_cast<OpenGLDriverBase const*>(driver);
#if UTILS_HAS_RTTI
FILAMENT_CHECK_POSTCONDITION(dynamic_cast<OpenGLDriverBase const*>(driver))
<< "Driver* has not been allocated with OpenGLPlatform";
#endif
return p->getRendererString();
}
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
@@ -121,14 +146,24 @@ OpenGLPlatform::ExternalTexture* OpenGLPlatform::createExternalImageTexture() no
return nullptr;
}
void OpenGLPlatform::destroyExternalImage(
void OpenGLPlatform::destroyExternalImageTexture(
UTILS_UNUSED ExternalTexture* texture) noexcept {
}
void OpenGLPlatform::retainExternalImage(
UTILS_UNUSED ExternalImageHandleRef externalImage) noexcept {
}
void OpenGLPlatform::retainExternalImage(
UTILS_UNUSED void* externalImage) noexcept {
}
bool OpenGLPlatform::setExternalImage(
UTILS_UNUSED ExternalImageHandleRef externalImage,
UTILS_UNUSED ExternalTexture* texture) noexcept {
return false;
}
bool OpenGLPlatform::setExternalImage(
UTILS_UNUSED void* externalImage,
UTILS_UNUSED ExternalTexture* texture) noexcept {
@@ -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);
@@ -295,7 +297,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
clearGlError();
// success!!
return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig);
return createDefaultDriver(this, sharedContext, driverConfig);
error:
// if we're here, we've failed
@@ -549,7 +551,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
return sc;
}
void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
if (sc->sur != EGL_NO_SURFACE) {
@@ -562,7 +564,7 @@ void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
}
bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept {
bool PlatformEGL::isSwapChainProtected(SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
@@ -583,10 +585,10 @@ bool PlatformEGL::makeCurrent(ContextType type,
return success == EGL_TRUE ? true : false;
}
void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept {
void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
SwapChain* readSwapChain,
Invocable<void()> preContextChange,
Invocable<void(size_t index)> postContextChange) noexcept {
assert_invariant(drawSwapChain);
assert_invariant(readSwapChain);
@@ -645,7 +647,7 @@ void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
}
}
void PlatformEGL::commit(Platform::SwapChain* swapChain) noexcept {
void PlatformEGL::commit(SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
if (sc->sur != EGL_NO_SURFACE) {
@@ -668,7 +670,7 @@ Platform::Fence* PlatformEGL::createFence() noexcept {
return f;
}
void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept {
void PlatformEGL::destroyFence(Fence* fence) noexcept {
#ifdef EGL_KHR_reusable_sync
EGLSyncKHR sync = (EGLSyncKHR) fence;
if (sync != EGL_NO_SYNC_KHR) {
@@ -678,7 +680,7 @@ void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept {
}
FenceStatus PlatformEGL::waitFence(
Platform::Fence* fence, uint64_t timeout) noexcept {
Fence* fence, uint64_t timeout) noexcept {
#ifdef EGL_KHR_reusable_sync
EGLSyncKHR sync = (EGLSyncKHR) fence;
if (sync != EGL_NO_SYNC_KHR) {
@@ -699,16 +701,10 @@ FenceStatus PlatformEGL::waitFence(
OpenGLPlatform::ExternalTexture* PlatformEGL::createExternalImageTexture() noexcept {
ExternalTexture* outTexture = new(std::nothrow) ExternalTexture{};
glGenTextures(1, &outTexture->id);
if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) {
outTexture->target = GL_TEXTURE_EXTERNAL_OES;
} else {
// if texture external is not supported, revert to texture 2d
outTexture->target = GL_TEXTURE_2D;
}
return outTexture;
}
void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept {
void PlatformEGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
glDeleteTextures(1, &texture->id);
delete texture;
}
@@ -728,6 +724,18 @@ bool PlatformEGL::setExternalImage(void* externalImage,
return true;
}
Platform::ExternalImageHandle PlatformEGL::createExternalImage(EGLImageKHR eglImage) noexcept {
auto* const p = new(std::nothrow) ExternalImageEGL;
p->eglImage = eglImage;
return ExternalImageHandle{p};
}
bool PlatformEGL::setExternalImage(ExternalImageHandleRef externalImage,
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
auto const* const eglExternalImage = static_cast<ExternalImageEGL const*>(externalImage.get());
return setExternalImage(eglExternalImage->eglImage, texture);
}
// -----------------------------------------------------------------------------------------------
void PlatformEGL::initializeGlExtensions() noexcept {
@@ -738,7 +746,7 @@ void PlatformEGL::initializeGlExtensions() noexcept {
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
}
EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept {
EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept {
switch (type) {
case ContextType::NONE:
return EGL_NO_CONTEXT;
@@ -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>
+21 -8
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;
}
@@ -161,13 +163,24 @@ public:
return mProtectedMemorySupported;
}
inline bool isImageView2DOn3DImageSupported() const noexcept {
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
}
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
};
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
};
VkPhysicalDevicePortabilitySubsetFeaturesKHR mPortabilitySubsetFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
// By default, on platforms where we don't have portability subset, then this feature must
// exists. We only fill this struct only when portability subset is needed (i.e.
// non-conformant vulkan implementation).
.imageView2DOn3DImage = VK_TRUE,
};
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;
@@ -175,8 +188,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;
+50 -24
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,13 +573,13 @@ 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);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
1, metadata.width, metadata.height, usage, mStagePool);
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
texture.inc();
}
@@ -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;
+22 -12
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>());
}
}
@@ -126,6 +128,15 @@ fvkmemory::resource_ptr<VulkanTexture> initMsaaTexture(
return msTexture;
}
VulkanAttachment createSwapchainAttachment(const fvkmemory::resource_ptr<VulkanTexture> texture) {
return VulkanAttachment {
.texture = texture,
.level = 0,
.layerCount = static_cast<uint8_t>(texture ? texture->getPrimaryViewRange().layerCount : 1),
.layer = 0,
};
}
} // anonymous namespace
void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr<VulkanTexture> texture) {
@@ -206,7 +217,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;
}
@@ -272,22 +283,21 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
height = extent.height;
mProtected = swapchain->isProtected();
VulkanAttachment color = {};
color.texture = swapchain->getCurrentColor();
VulkanAttachment color = createSwapchainAttachment(swapchain->getCurrentColor());
mInfo->attachments = {color};
auto& fbkey = mInfo->fbkey;
auto& rpkey = mInfo->rpkey;
rpkey.colorFormat[0] = color.getFormat();
rpkey.viewCount = color.layerCount;
fbkey.width = width;
fbkey.height = height;
fbkey.color[0] = color.getImageView();
fbkey.resolve[0] = VK_NULL_HANDLE;
if (swapchain->getDepth()) {
VulkanAttachment depth = {};
depth.texture = swapchain->getDepth();
VulkanAttachment depth = createSwapchainAttachment(swapchain->getDepth());
mInfo->attachments.push_back(depth);
mInfo->depthIndex = 1;
@@ -314,8 +324,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 +508,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 -18
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();
@@ -217,12 +218,6 @@ struct VulkanProgram : public HwProgram, fvkmemory::Resource {
mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value);
}
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
inline utils::FixedCapacityVector<std::string> const& getBindingToName() const {
return mInfo->bindingToName;
}
#endif
// TODO: handle compute shaders.
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
static constexpr uint8_t const MAX_SHADER_MODULES = 2;
@@ -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)
@@ -40,6 +40,8 @@ VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const&
mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize),
mTransitionSwapChainImageLayoutForPresent(
platform->getCustomization().transitionSwapChainImageLayoutForPresent),
mLayerCount(1),
mCurrentSwapIndex(0),
mAcquired(false),
mIsFirstRenderPass(true) {
swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent);
@@ -76,17 +78,18 @@ void VulkanSwapChain::update() {
for (auto const color: bundle.colors) {
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, colorUsage,
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, colorUsage,
mStagePool);
mColors.push_back(colorTexture);
}
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, depthUsage,
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, depthUsage,
mStagePool);
mExtent = bundle.extent;
mLayerCount = bundle.layerCount;
}
void VulkanSwapChain::present() {
@@ -97,7 +100,7 @@ void VulkanSwapChain::present() {
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
.layerCount = mLayerCount,
};
mColors[mCurrentSwapIndex]->transitionLayout(&commands, subresources, VulkanLayout::PRESENT);
}
@@ -96,6 +96,7 @@ private:
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
fvkmemory::resource_ptr<VulkanTexture> mDepth;
VkExtent2D mExtent;
uint32_t mLayerCount;
uint32_t mCurrentSwapIndex;
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
bool mAcquired;
+52 -31
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>
@@ -144,6 +144,16 @@ inline VulkanLayout getDefaultLayoutImpl(VkImageUsageFlags vkusage) {
return getDefaultLayoutImpl(usage);
}
SamplerType getSamplerTypeFromDepth(uint32_t const depth) {
return depth > 1 ? SamplerType::SAMPLER_2D_ARRAY
: SamplerType::SAMPLER_2D;
}
uint8_t getLayerCountFromDepth(uint32_t const depth) {
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
}
} // anonymous namespace
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
@@ -152,7 +162,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),
@@ -165,12 +175,12 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
uint32_t height, TextureUsage tusage, VulkanStagePool& stagePool)
: HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED,
uint32_t height, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
: HwTexture(getSamplerTypeFromDepth(depth), 1, samples, width, height, depth, TextureFormat::UNUSED,
tusage),
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D),
1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D),
/*mipLevels=*/1, getLayerCountFromDepth(depth), getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
mState->mTextureImage = image;
mState->mTextureImageMemory = memory;
mPrimaryViewRange = mState->mFullViewRange;
@@ -184,8 +194,8 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
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{
@@ -198,11 +208,20 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = 0,
};
if (target == SamplerType::SAMPLER_CUBEMAP) {
if (target == SamplerType::SAMPLER_3D && any(tusage & TextureUsage::ALL_ATTACHMENTS)) {
if (context.isImageView2DOn3DImageSupported()) {
// Note that VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is only meant to create 2D views of
// a 3D image in the case where the image is the render target. So, for example, it's
// not meant to allow for 2D views that can be used with a sampler.
imageInfo.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
} else {
FVK_LOGW << "Note: creating 2D views on 3D image is not available on this platform. "
<< "i.e. we cannot render to slices of a 3D image" << utils::io::endl;
}
} else if (target == SamplerType::SAMPLER_CUBEMAP) {
imageInfo.arrayLayers = 6;
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
if (target == SamplerType::SAMPLER_2D_ARRAY) {
} else if (target == SamplerType::SAMPLER_2D_ARRAY) {
imageInfo.arrayLayers = depth;
imageInfo.extent.depth = 1;
// NOTE: We do not use VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT here because:
@@ -246,9 +265,9 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
// Validate that the format is actually sampleable.
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, state->mVkFormat, &props);
vkGetPhysicalDeviceFormatProperties(physicalDevice, mState->mVkFormat, &props);
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << state->mVkFormat << " is not "
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
"sampleable with optimal tiling." << utils::io::endl;
}
#endif
@@ -281,16 +300,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 +421,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 +481,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 +528,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 +577,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 +620,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 +635,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,
@@ -629,15 +649,16 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
if (hasTransitions) {
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
<< range.levelCount << ")" << " from=" << oldLayout << " to=" << newLayout
<< " format=" << state->mVkFormat << " depth=" << isVkDepthFormat(state->mVkFormat)
<< " format=" << mState->mVkFormat << " depth="
<< fvkutils::isVkDepthFormat(mState->mVkFormat)
<< " slice-by-slice=" << transitionSliceBySlice << utils::io::endl;
#endif
} else {
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
<< range.levelCount << ")" << " to=" << newLayout
<< " is skipped because of no change in layout" << utils::io::endl;
@@ -650,7 +671,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 +694,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,
+2 -2
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>
@@ -94,7 +94,7 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
// The texture will never destroy the given VkImage, but it does manages its subresources.
VulkanTexture(VkDevice device, VmaAllocator allocator,
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage tusage, VulkanStagePool& stagePool);
// Constructor for creating a texture view for wrt specific mip range
@@ -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;
};
@@ -18,10 +18,11 @@
#include <backend/DriverEnums.h>
#include "vulkan/VulkanContext.h"
#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>
@@ -68,7 +69,7 @@ FixedCapacityVector<const char*> getEnabledLayers() {
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
const FixedCapacityVector<VkLayerProperties> availableLayers
= filament::backend::enumerate(vkEnumerateInstanceLayerProperties);
= fvkutils::enumerate(vkEnumerateInstanceLayerProperties);
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
for (auto const& desired: DESIRED_LAYERS) {
@@ -84,6 +85,13 @@ FixedCapacityVector<const char*> getEnabledLayers() {
}
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
template<typename StructA, typename StructB>
StructA* chainStruct(StructA* structA, StructB* structB) {
structB->pNext = const_cast<void*>(structA->pNext);
structA->pNext = (void*) structB;
return structA;
}
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
// Print some driver or MoltenVK information if it is available.
if (vkGetPhysicalDeviceProperties2) {
@@ -92,8 +100,8 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
};
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
.pNext = &driverProperties,
};
chainStruct(&physicalDeviceProperties2, &driverProperties);
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
<< driverProperties.driverInfo << utils::io::endl;
@@ -126,7 +134,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. "
@@ -143,7 +151,7 @@ void printDepthFormats(VkPhysicalDevice device) {
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
FVK_LOGI << "Sampleable depth formats: ";
for (VkFormat format : ALL_VK_FORMATS) {
for (VkFormat format : fvkutils::ALL_VK_FORMATS) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(device, format, &props);
if ((props.optimalTilingFeatures & required) == required) {
@@ -172,7 +180,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 };
@@ -194,7 +202,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
#endif
// We only support external image for Android for now, but nothing bars us from
// We only support external image for Android for now, but nothing bars us from
// supporting other platforms.
#if defined(__ANDROID__)
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
@@ -212,7 +220,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 };
@@ -231,7 +239,9 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
VkInstance createInstance(ExtensionSet const& requiredExts) {
VkInstance instance;
VkInstanceCreateInfo instanceCreateInfo = {};
VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
};
bool validationFeaturesSupported = false;
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -239,7 +249,7 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
if (!enabledLayers.empty()) {
// If layers are supported, Check if VK_EXT_validation_features is supported.
FixedCapacityVector<VkExtensionProperties> const availableValidationExts
= filament::backend::enumerate(vkEnumerateInstanceExtensionProperties,
= fvkutils::enumerate(vkEnumerateInstanceExtensionProperties,
"VK_LAYER_KHRONOS_validation");
for (auto const& extProps: availableValidationExts) {
if (!strcmp(extProps.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) {
@@ -282,7 +292,6 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
appInfo.pEngineName = "Filament";
appInfo.apiVersion
= VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0);
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pApplicationInfo = &appInfo;
instanceCreateInfo.enabledExtensionCount = enabledExtensionCount;
instanceCreateInfo.ppEnabledExtensionNames = ppEnabledExtensions;
@@ -290,16 +299,17 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}
VkValidationFeaturesEXT features = {};
VkValidationFeaturesEXT features = {
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
};
VkValidationFeatureEnableEXT enables[] = {
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
};
if (validationFeaturesSupported) {
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
features.pEnabledValidationFeatures = enables;
instanceCreateInfo.pNext = &features;
chainStruct(&instanceCreateInfo, &features);
}
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
@@ -310,11 +320,13 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions) {
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
bool requestImageView2DOn3DImage) {
VkDevice device;
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
const float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {};
float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
};
FixedCapacityVector<const char*> requestExtensions;
requestExtensions.reserve(deviceExtensions.size() + 1);
@@ -323,6 +335,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
for (auto const& ext: deviceExtensions) {
requestExtensions.push_back(ext.data());
}
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
deviceQueueCreateInfo[0].queueCount = 1;
@@ -334,7 +347,6 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
deviceQueueCreateInfo[1].queueCount = 1;
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority[0];
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
bool const hasProtectedQueue = protectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX;
deviceCreateInfo.queueCreateInfoCount = hasProtectedQueue ? 2 : 1;
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
@@ -353,42 +365,35 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
void* pNext = nullptr;
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
.pNext = nullptr,
.imageViewFormatSwizzle = VK_TRUE,
.mutableComparisonSamplers = VK_TRUE,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
.imageViewFormatSwizzle = VK_TRUE,
.imageView2DOn3DImage = requestImageView2DOn3DImage ? VK_TRUE : VK_FALSE,
.mutableComparisonSamplers = VK_TRUE,
};
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
portability.pNext = pNext;
pNext = &portability;
chainStruct(&deviceCreateInfo, &portability);
}
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.pNext = nullptr,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE,
};
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
multiview.pNext = pNext;
pNext = &multiview;
chainStruct(&deviceCreateInfo, &multiview);
}
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
.protectedMemory = VK_TRUE,
};
if (hasProtectedQueue) {
// Enable protected memory, if requested.
protectedMemory.protectedMemory = VK_TRUE;
protectedMemory.pNext = pNext;
pNext = &protectedMemory;
chainStruct(&deviceCreateInfo, &protectedMemory);
}
deviceCreateInfo.pNext = pNext;
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
@@ -473,7 +478,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;
@@ -501,14 +506,14 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
// Does the device have any command queues that support graphics?
// In theory, we should also ensure that the device supports presentation of our
// particular VkSurface, but we don't have a VkSurface yet, so we'll skip this requirement.
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
== INVALID_VK_INDEX) {
continue;
}
// 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 +565,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 +584,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 +602,7 @@ VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) {
}
}
}
VkFormatList ret(selectedFormats.size());
fvkutils::VkFormatList ret(selectedFormats.size());
std::copy(selectedFormats.begin(), selectedFormats.end(), ret.begin());
return ret;
}
@@ -721,14 +726,11 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
VkPhysicalDeviceProtectedMemoryFeatures queryProtectedMemoryFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
};
// Chain to the pNext linked list
queryProtectedMemoryFeatures.pNext = context.mPhysicalDeviceFeatures.pNext;
context.mPhysicalDeviceFeatures.pNext = &queryProtectedMemoryFeatures;
VkPhysicalDeviceProtectedMemoryProperties protectedMemoryProperties = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
};
protectedMemoryProperties.pNext = context.mPhysicalDeviceProperties.pNext;
context.mPhysicalDeviceProperties.pNext = &protectedMemoryProperties;
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
@@ -738,17 +740,17 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
mImpl->mGraphicsQueueFamilyIndex
= mImpl->mGraphicsQueueFamilyIndex == INVALID_VK_INDEX
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
VK_QUEUE_GRAPHICS_BIT)
: mImpl->mGraphicsQueueFamilyIndex;
assert_invariant(mImpl->mGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
// We know we need to allocate the protected version of the VK objects
context.mProtectedMemorySupported =
context.mProtectedMemorySupported =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
if (context.mProtectedMemorySupported) {
mImpl->mProtectedGraphicsQueueFamilyIndex
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
assert_invariant(mImpl->mProtectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
}
@@ -768,7 +770,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
// Applying the same logic to the protected queue index (Not sure about shared context and protection)
mImpl->mProtectedGraphicsQueueIndex
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
mImpl->mProtectedGraphicsQueueIndex;
ExtensionSet deviceExts;
@@ -785,11 +787,23 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
}
}
mImpl->mDevice
= mImpl->mDevice == VK_NULL_HANDLE ? createLogicalDevice(mImpl->mPhysicalDevice,
context.mPhysicalDeviceFeatures, mImpl->mGraphicsQueueFamilyIndex,
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts)
: mImpl->mDevice;
bool requestPortabilitySubsetImageView2DOn3DImage = false;
if (setContains(deviceExts, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
// We are on a non-conformant vulkan implementation so we need to ascertain if the features
// we need are available.
chainStruct(&context.mPhysicalDeviceFeatures, &context.mPortabilitySubsetFeatures);
vkGetPhysicalDeviceFeatures2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceFeatures);
requestPortabilitySubsetImageView2DOn3DImage =
context.mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
}
mImpl->mDevice =
mImpl->mDevice == VK_NULL_HANDLE
? createLogicalDevice(mImpl->mPhysicalDevice, context.mPhysicalDeviceFeatures,
mImpl->mGraphicsQueueFamilyIndex,
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts,
requestPortabilitySubsetImageView2DOn3DImage)
: mImpl->mDevice;
assert_invariant(mImpl->mDevice != VK_NULL_HANDLE);
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,
@@ -806,9 +820,16 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
}
// Store the extension support in the context
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
if (!mImpl->mSharedContext) {
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
} else {
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
context.mDebugMarkersSupported = scontext->debugMarkersSupported;
context.mMultiviewEnabled = scontext->multiviewSupported;
}
// Check the availability of lazily allocated memory
{
@@ -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;
@@ -180,7 +214,7 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange&
case filament::backend::VulkanLayout::VALUE: { \
out << #VALUE; \
out << " [" \
<< filament::backend::imgutil::getVkLayout( \
<< filament::backend::fvkutils::getVkLayout( \
filament::backend::VulkanLayout::VALUE) \
<< "]"; \
break; \
@@ -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
+12
View File
@@ -17,6 +17,7 @@
#ifndef TNT_FILAMENT_ENGINE_H
#define TNT_FILAMENT_ENGINE_H
#include <filament/FilamentAPI.h>
#include <backend/DriverEnums.h>
@@ -32,6 +33,7 @@
#include <stdint.h>
#include <stddef.h>
namespace utils {
class Entity;
class EntityManager;
@@ -40,6 +42,10 @@ class JobSystem;
namespace filament {
namespace backend {
class Driver;
} // backend
class BufferObject;
class Camera;
class ColorGrading;
@@ -183,6 +189,7 @@ public:
using DriverConfig = backend::Platform::DriverConfig;
using FeatureLevel = backend::FeatureLevel;
using StereoscopicType = backend::StereoscopicType;
using Driver = backend::Driver;
/**
* Config is used to define the memory footprint used by the engine, such as the
@@ -582,6 +589,11 @@ public:
static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token);
#endif
/**
* @return the Driver instance used by this Engine.
* @see OpenGLPlatform
*/
backend::Driver const* UTILS_NONNULL getDriver() const noexcept;
/**
* Destroy the Engine instance and all associated resources.
+20 -9
View File
@@ -121,7 +121,7 @@ public:
/** inline helper to provide the name as a null-terminated string literal */
template<typename T, typename = is_supported_parameter_t<T>>
void setParameter(StringLiteral name, T const& value) {
void setParameter(StringLiteral const name, T const& value) {
setParameter<T>(name.data, name.size, value);
}
@@ -148,14 +148,14 @@ public:
/** inline helper to provide the name as a null-terminated string literal */
template<typename T, typename = is_supported_parameter_t<T>>
void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t count) {
void setParameter(StringLiteral const name, const T* UTILS_NONNULL values, size_t const count) {
setParameter<T>(name.data, name.size, values, count);
}
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_parameter_t<T>>
void setParameter(const char* UTILS_NONNULL name,
const T* UTILS_NONNULL values, size_t count) {
const T* UTILS_NONNULL values, size_t const count) {
setParameter<T>(name, strlen(name), values, count);
}
@@ -176,7 +176,7 @@ public:
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler);
/** inline helper to provide the name as a null-terminated string literal */
void setParameter(StringLiteral name,
void setParameter(StringLiteral const name,
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) {
setParameter(name.data, name.size, texture, sampler);
}
@@ -202,12 +202,12 @@ public:
RgbType type, math::float3 color);
/** inline helper to provide the name as a null-terminated string literal */
void setParameter(StringLiteral name, RgbType type, math::float3 color) {
void setParameter(StringLiteral const name, RgbType const type, math::float3 const color) {
setParameter(name.data, name.size, type, color);
}
/** inline helper to provide the name as a null-terminated C string */
void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) {
void setParameter(const char* UTILS_NONNULL name, RgbType const type, math::float3 const color) {
setParameter(name, strlen(name), type, color);
}
@@ -226,12 +226,12 @@ public:
RgbaType type, math::float4 color);
/** inline helper to provide the name as a null-terminated string literal */
void setParameter(StringLiteral name, RgbaType type, math::float4 color) {
void setParameter(StringLiteral const name, RgbaType const type, math::float4 const color) {
setParameter(name.data, name.size, type, color);
}
/** inline helper to provide the name as a null-terminated C string */
void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) {
void setParameter(const char* UTILS_NONNULL name, RgbaType const type, math::float4 const color) {
setParameter(name, strlen(name), type, color);
}
@@ -251,7 +251,7 @@ public:
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_parameter_t<T>>
T getParameter(StringLiteral name) const {
T getParameter(StringLiteral const name) const {
return getParameter<T>(name.data, name.size);
}
@@ -376,11 +376,22 @@ public:
*/
void setCullingMode(CullingMode culling) noexcept;
/**
* Overrides the default triangle culling state that was set on the material separately for the
* color and shadow passes
*/
void setCullingMode(CullingMode colorPassCullingMode, CullingMode shadowPassCullingMode) noexcept;
/**
* Returns the face culling mode.
*/
CullingMode getCullingMode() const noexcept;
/**
* Returns the face culling mode for the shadow passes.
*/
CullingMode getShadowCullingMode() const noexcept;
/**
* Overrides the default color-buffer write state that was set on the material.
*/
+5
View File
@@ -141,6 +141,11 @@ public:
*/
void removeEntities(const utils::Entity* UTILS_NONNULL entities, size_t count);
/**
* Remove all entities to the Scene.
*/
void removeAllEntities() noexcept;
/**
* Returns the total number of Entities in the Scene, whether alive or not.
* @return Total number of Entities in the Scene.
+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
+4
View File
@@ -68,6 +68,10 @@ Engine* Engine::getEngine(void* token) {
}
#endif
Driver const* Engine::getDriver() const noexcept {
return std::addressof(downcast(this)->getDriver());
}
void Engine::destroy(Engine** pEngine) {
if (pEngine) {
Engine* engine = *pEngine;
+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);
}
+32 -3
View File
@@ -17,6 +17,26 @@
#include <filament/MaterialInstance.h>
#include "details/Material.h"
#include "details/MaterialInstance.h"
#include <filament/Color.h>
#include <filament/MaterialEnums.h>
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <algorithm>
#include <string_view>
#include <stddef.h>
#include <stdint.h>
namespace filament {
@@ -85,7 +105,7 @@ void MaterialInstance::setParameter(const char* name, size_t nameLength, T const
template<>
UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, size_t const nameLength, bool const& v) {
// this kills tail-call optimization
setParameter(name, nameLength, (uint32_t)v);
setParameter(name, nameLength, uint32_t(v));
}
template<>
@@ -125,8 +145,8 @@ template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char*
// ------------------------------------------------------------------------------------------------
template <typename T, typename>
void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* value, size_t count) {
downcast(this)->setParameterImpl({ name, nameLength }, value, count);
void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* values, size_t count) {
downcast(this)->setParameterImpl({ name, nameLength }, values, count);
}
template<>
@@ -272,6 +292,11 @@ void MaterialInstance::setCullingMode(CullingMode const culling) noexcept {
downcast(this)->setCullingMode(culling);
}
void MaterialInstance::setCullingMode(CullingMode const colorPassCullingMode,
CullingMode const shadowPassCullingMode) noexcept {
downcast(this)->setCullingMode(colorPassCullingMode, shadowPassCullingMode);
}
void MaterialInstance::setColorWrite(bool const enable) noexcept {
downcast(this)->setColorWrite(enable);
}
@@ -353,6 +378,10 @@ CullingMode MaterialInstance::getCullingMode() const noexcept {
return downcast(this)->getCullingMode();
}
CullingMode MaterialInstance::getShadowCullingMode() const noexcept {
return downcast(this)->getShadowCullingMode();
}
bool MaterialInstance::isColorWriteEnabled() const noexcept {
return downcast(this)->isColorWriteEnabled();
}
+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;
}
+11 -4
View File
@@ -807,7 +807,13 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
cmd.key &= ~Z_BUCKET_MASK;
cmd.key |= makeField(distanceBits >> 22u, Z_BUCKET_MASK, Z_BUCKET_SHIFT);
}
*curr = cmd;
// cancel command if both front and back faces are culled
curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK);
} else if constexpr (isDepthPass) {
const CullingMode cullingMode = hasShadowing ? mi->getShadowCullingMode() : mi->getCullingMode();
const RasterState rs = ma->getRasterState();
const TransparencyMode mode = mi->getTransparencyMode();
const BlendingMode blendingMode = ma->getBlendingMode();
@@ -816,7 +822,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
const bool isPickingVariant = Variant::isPickingVariant(variant);
cmd.key |= mi->getSortingKey(); // already all set-up for direct or'ing
cmd.info.rasterState.culling = mi->getCullingMode();
cmd.info.rasterState.culling = cullingMode;
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
cmd.info.rasterState.depthWrite = (1 // only keep bit 0
@@ -825,11 +831,12 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
& !(filterTranslucentObjects & translucent)
& !(depthFilterAlphaMaskedObjects & rs.alphaToCoverage))
| writeDepthForShadowCasters;
*curr = cmd;
// cancel command if both front and back faces are culled
curr->key |= select(cullingMode == CullingMode::FRONT_AND_BACK);
}
*curr = cmd;
// cancel command if both front and back faces are culled
curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK);
++curr;
}
}
+4
View File
@@ -55,6 +55,10 @@ void Scene::removeEntities(const Entity* entities, size_t const count) {
downcast(this)->removeEntities(entities, count);
}
void Scene::removeAllEntities() noexcept {
downcast(this)->removeAllEntities();
}
size_t Scene::getEntityCount() const noexcept {
return downcast(this)->getEntityCount();
}
+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));
+110 -78
View File
@@ -25,7 +25,9 @@
#include "details/Fence.h"
#include "details/IndexBuffer.h"
#include "details/IndirectLight.h"
#include "details/InstanceBuffer.h"
#include "details/Material.h"
#include "details/MorphTargetBuffer.h"
#include "details/Renderer.h"
#include "details/Scene.h"
#include "details/SkinningBuffer.h"
@@ -36,28 +38,39 @@
#include "details/VertexBuffer.h"
#include "details/View.h"
#include <filament/ColorGrading.h>
#include <filament/Engine.h>
#include <filament/MaterialEnums.h>
#include <private/filament/DescriptorSets.h>
#include <private/filament/EngineEnums.h>
#include <private/filament/Variant.h>
#include <private/backend/PlatformFactory.h>
#include <backend/DriverEnums.h>
#include <utils/Allocator.h>
#include <utils/CallStack.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Invocable.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/PrivateImplementation-impl.h>
#include <utils/Systrace.h>
#include <utils/ThreadUtils.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <algorithm>
#include <chrono>
#include <initializer_list>
#include <memory>
#include <mutex>
#include <new>
#include <optional>
#include <thread>
#include <string_view>
@@ -66,6 +79,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "generated/resources/materials.h"
@@ -101,7 +115,7 @@ Engine* FEngine::create(Builder const& builder) {
// Normally we launch a thread and create the context and Driver from there (see FEngine::loop).
// In the single-threaded case, we do so in the here and now.
if (!UTILS_HAS_THREADING) {
if constexpr (!UTILS_HAS_THREADING) {
Platform* platform = builder->mPlatform;
void* const sharedContext = builder->mSharedContext;
@@ -144,7 +158,7 @@ Engine* FEngine::create(Builder const& builder) {
// now we can initialize the largest part of the engine
instance->init();
if (!UTILS_HAS_THREADING) {
if constexpr (!UTILS_HAS_THREADING) {
instance->execute();
}
@@ -163,7 +177,7 @@ void FEngine::create(Builder const& builder, Invocable<void(void*)>&& callback)
instance->mDriverThread = std::thread(&FEngine::loop, instance);
// launch a thread to call the callback -- so it can't do any damage.
std::thread callbackThread = std::thread([instance, callback = std::move(callback)]() {
std::thread callbackThread = std::thread([instance, callback = std::move(callback)] {
instance->mDriverBarrier.await();
callback(instance);
});
@@ -196,7 +210,7 @@ FEngine* FEngine::getEngine(void* token) {
#endif
// these must be static because only a pointer is copied to the render stream
// These must be static because only a pointer is copied to the render stream
// Note that these coordinates are specified in OpenGL clip space. Other backends can transform
// these in the vertex shader as needed.
static constexpr float4 sFullScreenTriangleVertices[3] = {
@@ -206,7 +220,7 @@ static constexpr float4 sFullScreenTriangleVertices[3] = {
};
// these must be static because only a pointer is copied to the render stream
static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
static constexpr uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
FEngine::FEngine(Builder const& builder) :
mBackend(builder->mBackend),
@@ -216,7 +230,6 @@ FEngine::FEngine(Builder const& builder) :
mPostProcessManager(*this),
mEntityManager(EntityManager::get()),
mRenderableManager(*this),
mTransformManager(),
mLightManager(*this),
mCameraManager(*this),
mCommandBufferQueue(
@@ -274,7 +287,7 @@ uint32_t FEngine::getJobSystemThreadPoolSize(Config const& config) noexcept {
}
// 1 thread for the user, 1 thread for the backend
int threadCount = (int)std::thread::hardware_concurrency() - 2;
int threadCount = int(std::thread::hardware_concurrency()) - 2;
// make sure we have at least 1 thread though
threadCount = std::max(1, threadCount);
return threadCount;
@@ -347,8 +360,8 @@ void FEngine::init() {
}
// initialize the dummy textures so that their contents are not undefined
static const uint32_t zeroes[6] = {0};
static const uint32_t ones = 0xffffffff;
static constexpr uint32_t zeroes[6] = {};
static constexpr uint32_t ones = 0xffffffff;
mDefaultIblTexture = downcast(Texture::Builder()
.width(1).height(1).levels(1)
@@ -360,7 +373,7 @@ void FEngine::init() {
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
// 3 bands = 9 float3
const float sh[9 * 3] = { 0.0f };
constexpr float sh[9 * 3] = { 0.0f };
mDefaultIbl = downcast(IndirectLight::Builder()
.irradiance(3, reinterpret_cast<const float3*>(sh))
.build(*this));
@@ -427,10 +440,10 @@ void FEngine::init() {
#endif
break;
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
float3 dummyPositions[1] = {};
short4 dummyTangents[1] = {};
constexpr float3 dummyPositions[1] = {};
constexpr short4 dummyTangents[1] = {};
mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0);
mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0);
@@ -453,7 +466,7 @@ void FEngine::init() {
mPostProcessManager.init();
mDebugRegistry.registerProperty("d.shadowmap.debug_directional_shadowmap",
&debug.shadowmap.debug_directional_shadowmap, [this]() {
&debug.shadowmap.debug_directional_shadowmap, [this] {
mMaterials.forEach([this](FMaterial* material) {
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
@@ -469,7 +482,7 @@ void FEngine::init() {
});
mDebugRegistry.registerProperty("d.lighting.debug_froxel_visualization",
&debug.lighting.debug_froxel_visualization, [this]() {
&debug.lighting.debug_froxel_visualization, [this] {
mMaterials.forEach([this](FMaterial* material) {
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
@@ -607,7 +620,7 @@ void FEngine::shutdown() {
// now wait for all pending commands to be executed and the thread to exit
mCommandBufferQueue.requestExit();
if (!UTILS_HAS_THREADING) {
if constexpr (!UTILS_HAS_THREADING) {
execute();
getDriverApi().terminate();
} else {
@@ -638,13 +651,13 @@ void FEngine::prepare() {
DriverApi& driver = getDriverApi();
for (auto& materialInstanceList: mMaterialInstances) {
materialInstanceList.second.forEach([&driver](FMaterialInstance* item) {
materialInstanceList.second.forEach([&driver](FMaterialInstance const* item) {
item->commit(driver);
});
}
mMaterials.forEach([](FMaterial* material) {
#if FILAMENT_ENABLE_MATDBG
#if FILAMENT_ENABLE_MATDBG // NOLINT(*-include-cleaner)
material->checkProgramEdits();
#endif
});
@@ -668,7 +681,7 @@ void FEngine::flushAndWait() {
flushAndWait(FENCE_WAIT_FOR_EVER);
}
bool FEngine::flushAndWait(uint64_t timeout) {
bool FEngine::flushAndWait(uint64_t const timeout) {
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
<< "Cannot call Engine::flushAndWait() when rendering thread is paused!";
@@ -706,28 +719,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 +740,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 // NOLINT(*-include-cleaner)
#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;
@@ -760,9 +792,9 @@ int FEngine::loop() {
return 0;
}
void FEngine::flushCommandBuffer(CommandBufferQueue& commandQueue) {
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
getDriver().purge();
commandQueue.flush();
commandBufferQueue.flush();
}
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
@@ -783,7 +815,7 @@ const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
*/
template<typename T, typename ... ARGS>
inline T* FEngine::create(ResourceList<T>& list,
T* FEngine::create(ResourceList<T>& list,
typename T::Builder const& builder, ARGS&& ... args) noexcept {
T* p = mHeapAllocator.make<T>(*this, builder, std::forward<ARGS>(args)...);
if (UTILS_LIKELY(p)) {
@@ -861,7 +893,7 @@ FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material,
const FMaterialInstance* other, const char* name) noexcept {
FMaterialInstance* p = mHeapAllocator.make<FMaterialInstance>(*this, other, name);
if (UTILS_LIKELY(p)) {
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
auto const pos = mMaterialInstances.emplace(material, "MaterialInstance");
pos.first->second.insert(p);
}
return p;
@@ -939,7 +971,7 @@ FCamera* FEngine::createCamera(Entity const entity) noexcept {
}
FCamera* FEngine::getCameraComponent(Entity const entity) noexcept {
auto ci = mCameraManager.getInstance(entity);
auto const ci = mCameraManager.getInstance(entity);
return ci ? mCameraManager.getCamera(ci) : nullptr;
}
@@ -992,16 +1024,16 @@ void FEngine::cleanupResourceListLocked(Lock& lock, ResourceList<T>&& list) {
template<typename T>
UTILS_ALWAYS_INLINE
inline bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
auto& l = const_cast<ResourceList<T>&>(list);
return l.find(ptr) != l.end();
}
template<typename T>
UTILS_ALWAYS_INLINE
inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
if (ptr == nullptr) return true;
bool const success = list.remove(ptr);
bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
if (p == nullptr) return true;
bool const success = list.remove(p);
#if UTILS_HAS_RTTI
auto typeName = CallStack::typeName<T>();
@@ -1011,19 +1043,19 @@ inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
#endif
if (ASSERT_PRECONDITION_NON_FATAL(success,
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
const_cast<T*>(ptr)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(ptr));
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
const_cast<T*>(p)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(p));
}
return success;
}
template<typename T, typename Lock>
UTILS_ALWAYS_INLINE
inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, ResourceList<T>& list) {
if (ptr == nullptr) return true;
bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>& list) {
if (p == nullptr) return true;
lock.lock();
bool const success = list.remove(ptr);
bool const success = list.remove(p);
lock.unlock();
#if UTILS_HAS_RTTI
@@ -1034,9 +1066,9 @@ inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, Resourc
#endif
if (ASSERT_PRECONDITION_NON_FATAL(success,
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
const_cast<T*>(ptr)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(ptr));
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
const_cast<T*>(p)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(p));
}
return success;
}
@@ -1129,11 +1161,11 @@ bool FEngine::destroy(const FInstanceBuffer* p){
}
UTILS_NOINLINE
bool FEngine::destroy(const FMaterial* ptr) {
if (ptr == nullptr) return true;
bool const success = terminateAndDestroy(ptr, mMaterials);
bool FEngine::destroy(const FMaterial* p) {
if (p == nullptr) return true;
bool const success = terminateAndDestroy(p, mMaterials);
if (UTILS_LIKELY(success)) {
auto pos = mMaterialInstances.find(ptr);
auto const pos = mMaterialInstances.find(p);
if (UTILS_LIKELY(pos != mMaterialInstances.cend())) {
mMaterialInstances.erase(pos);
}
@@ -1142,8 +1174,8 @@ bool FEngine::destroy(const FMaterial* ptr) {
}
UTILS_NOINLINE
bool FEngine::destroy(const FMaterialInstance* ptr) {
if (ptr == nullptr) return true;
bool FEngine::destroy(const FMaterialInstance* p) {
if (p == nullptr) return true;
// Check that the material instance we're destroying is not in use in the RenderableManager
// To do this, we currently need to inspect all render primitives in the RenderableManager
@@ -1159,13 +1191,13 @@ bool FEngine::destroy(const FMaterialInstance* ptr) {
for (size_t j = 0; j < primitiveCount; j++) {
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
if (features.engine.debug.assert_material_instance_in_use) {
FILAMENT_CHECK_PRECONDITION(mi != ptr)
FILAMENT_CHECK_PRECONDITION(mi != p)
<< "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
<< ri.asValue() << ", index=" << j << ")";
} else {
if (UTILS_UNLIKELY(mi == ptr)) {
if (UTILS_UNLIKELY(mi == p)) {
slog.e << "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
@@ -1177,11 +1209,11 @@ bool FEngine::destroy(const FMaterialInstance* ptr) {
}
}
if (ptr->isDefaultInstance()) return false;
auto pos = mMaterialInstances.find(ptr->getMaterial());
if (p->isDefaultInstance()) return false;
auto const pos = mMaterialInstances.find(p->getMaterial());
assert_invariant(pos != mMaterialInstances.cend());
if (pos != mMaterialInstances.cend()) {
return terminateAndDestroy(ptr, pos->second);
return terminateAndDestroy(p, pos->second);
}
// this shouldn't happen, this would be double-free
return false;
@@ -1234,7 +1266,7 @@ bool FEngine::isValid(const FMaterial* m, const FMaterialInstance* p) const {
}
// then find the material instance list for that material
auto it = mMaterialInstances.find(m);
auto const it = mMaterialInstances.find(m);
if (it == mMaterialInstances.end()) {
// this could happen if this material has no material instances at all
return false;
@@ -1323,7 +1355,7 @@ void* FEngine::streamAlloc(size_t const size, size_t const alignment) noexcept {
bool FEngine::execute() {
// wait until we get command buffers to be executed (or thread exit requested)
auto buffers = mCommandBufferQueue.waitForCommands();
auto const buffers = mCommandBufferQueue.waitForCommands();
if (UTILS_UNLIKELY(buffers.empty())) {
return false;
}
@@ -1362,7 +1394,7 @@ Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept {
Engine::FeatureLevel FEngine::setActiveFeatureLevel(FeatureLevel featureLevel) {
FILAMENT_CHECK_PRECONDITION(featureLevel <= getSupportedFeatureLevel())
<< "Feature level " << (unsigned)featureLevel << " not supported";
<< "Feature level " << unsigned(featureLevel) << " not supported";
FILAMENT_CHECK_PRECONDITION(mActiveFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1)
<< "Cannot adjust feature level beyond 0 at runtime";
return (mActiveFeatureLevel = std::max(mActiveFeatureLevel, featureLevel));
@@ -1381,7 +1413,7 @@ void FEngine::unprotected() noexcept {
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
}
bool FEngine::setFeatureFlag(char const* name, bool const value) noexcept {
bool FEngine::setFeatureFlag(char const* name, bool const value) const noexcept {
auto* const p = getFeatureFlagPtr(name);
if (p) {
*p = value;
@@ -1452,7 +1484,7 @@ Engine::Builder& Engine::Builder::feature(char const* name, bool const value) no
}
Engine::Builder& Engine::Builder::features(std::initializer_list<char const *> const list) noexcept {
for (auto name : list) {
for (auto const name : list) {
if (name) {
feature(name, true);
}
@@ -1481,15 +1513,15 @@ Engine::Config Engine::BuilderDetails::validateConfig(Config config) noexcept {
// Use at least the defaults set by the build system
config.minCommandBufferSizeMB = std::max(
config.minCommandBufferSizeMB,
(uint32_t)FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB);
uint32_t(FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
config.perFrameCommandsSizeMB = std::max(
config.perFrameCommandsSizeMB,
(uint32_t)FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB);
uint32_t(FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
config.perRenderPassArenaSizeMB = std::max(
config.perRenderPassArenaSizeMB,
(uint32_t)FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB);
uint32_t(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
config.commandBufferSizeMB = std::max(
config.commandBufferSizeMB,
+20 -18
View File
@@ -61,6 +61,8 @@
#include <filament/Texture.h>
#include <filament/VertexBuffer.h>
#include <backend/DriverEnums.h>
#include <utils/Allocator.h>
#include <utils/compiler.h>
#include <utils/CountDownLatch.h>
@@ -88,6 +90,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;
@@ -114,12 +124,11 @@ class ResourceAllocator;
*/
class FEngine : public Engine {
public:
inline void* operator new(std::size_t const size) noexcept {
void* operator new(std::size_t const size) noexcept {
return utils::aligned_alloc(size, alignof(FEngine));
}
inline void operator delete(void* p) noexcept {
void operator delete(void* p) noexcept {
utils::aligned_free(p);
}
@@ -252,20 +261,12 @@ 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 };
}
@@ -490,7 +491,7 @@ public:
backend::Handle<backend::HwTexture> getOneTextureArray() const { return mDummyOneTextureArray; }
backend::Handle<backend::HwTexture> getZeroTextureArray() const { return mDummyZeroTextureArray; }
static constexpr const size_t MiB = 1024u * 1024u;
static constexpr size_t MiB = 1024u * 1024u;
size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; }
size_t getCommandBufferSize() const noexcept { return mConfig.commandBufferSizeMB * MiB; }
size_t getPerFrameCommandsSize() const noexcept { return mConfig.perFrameCommandsSizeMB * MiB; }
@@ -510,15 +511,15 @@ public:
void resetBackendState() noexcept;
#endif
backend::Driver& getDriver() const noexcept { return *mDriver; }
private:
explicit FEngine(Builder const& builder);
void init();
void shutdown();
int loop();
void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue);
backend::Driver& getDriver() const noexcept { return *mDriver; }
void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue) const;
template<typename T>
bool isValid(const T* ptr, ResourceList<T> const& list) const;
@@ -681,6 +682,7 @@ public:
bool combine_multiview_images = false;
} stereo;
matdbg::DebugServer* server = nullptr;
fgviewer::DebugServer* fgviewerServer = nullptr;
} debug;
struct {
@@ -728,7 +730,7 @@ public:
return { mFeatures.data(), mFeatures.size() };
}
bool setFeatureFlag(char const* name, bool value) noexcept;
bool setFeatureFlag(char const* name, bool value) const noexcept;
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
};
+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);
+7 -7
View File
@@ -196,10 +196,10 @@ void FMaterialInstance::commit(DriverApi& driver) const {
for (auto const& [binding, p]: mTextureParameters) {
assert_invariant(p.texture);
// TODO: figure out a way to do this more efficiently (isValid() is a hashmap lookup)
FEngine& engine = mMaterial->getEngine();
FEngine const& engine = mMaterial->getEngine();
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
Handle<HwTexture> handle = p.texture->getHwHandleForSampling();
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
assert_invariant(handle);
mDescriptorSet.setSampler(binding, handle, p.params);
}
@@ -216,7 +216,7 @@ void FMaterialInstance::commit(DriverApi& driver) const {
void FMaterialInstance::setParameter(std::string_view const name,
Handle<HwTexture> texture, SamplerParams const params) {
auto binding = mMaterial->getSamplerBinding(name);
auto const binding = mMaterial->getSamplerBinding(name);
mDescriptorSet.setSampler(binding, texture, params);
}
@@ -243,7 +243,7 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
}
#endif
auto binding = mMaterial->getSamplerBinding(name);
auto const binding = mMaterial->getSamplerBinding(name);
if (texture && texture->textureHandleCanMutate()) {
mTextureParameters[binding] = { texture, sampler.getSamplerParams() };
} else {
@@ -328,13 +328,13 @@ const char* FMaterialInstance::getName() const noexcept {
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
std::call_once(mMissingSamplersFlag, [this]() {
std::call_once(mMissingSamplersFlag, [this] {
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
slog.w << "sampler parameters not set in MaterialInstance \""
<< mName.c_str_safe() << "\" or Material \""
<< mMaterial->getName().c_str_safe() << "\":\n";
mMissingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) {
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
return item.binding == binding;
});
// just safety-check, should never fail
@@ -368,7 +368,7 @@ void FMaterialInstance::fixMissingSamplers() const {
// here we need to set the samplers that are missing
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
missingSamplerDescriptors.forEachSetBit([this, &list](descriptor_binding_t binding) {
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
return item.binding == binding;
});
+11 -2
View File
@@ -94,6 +94,8 @@ public:
backend::CullingMode getCullingMode() const noexcept { return mCulling; }
backend::CullingMode getShadowCullingMode() const noexcept { return mShadowCulling; }
bool isColorWriteEnabled() const noexcept { return mColorWrite; }
bool isDepthWriteEnabled() const noexcept { return mDepthWrite; }
@@ -137,6 +139,11 @@ public:
void setCullingMode(CullingMode const culling) noexcept { mCulling = culling; }
void setCullingMode(CullingMode const color, CullingMode const shadow) noexcept {
mCulling = color;
mShadowCulling = shadow;
}
void setColorWrite(bool const enable) noexcept { mColorWrite = enable; }
void setDepthWrite(bool const enable) noexcept { mDepthWrite = enable; }
@@ -271,7 +278,9 @@ private:
float mSpecularAntiAliasingThreshold = 0.0f;
backend::CullingMode mCulling : 2;
backend::CullingMode mShadowCulling : 2;
backend::RasterState::DepthFunc mDepthFunc : 3;
bool mColorWrite : 1;
bool mDepthWrite : 1;
bool mHasScissor : 1;
@@ -283,8 +292,8 @@ private:
// Scissor rectangle is specified as: Left Bottom Width Height.
backend::Viewport mScissorRect = { 0, 0,
(uint32_t)std::numeric_limits<int32_t>::max(),
(uint32_t)std::numeric_limits<int32_t>::max()
uint32_t(std::numeric_limits<int32_t>::max()),
uint32_t(std::numeric_limits<int32_t>::max())
};
utils::CString mName;
+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);
+5
View File
@@ -546,6 +546,11 @@ void FScene::removeEntities(const Entity* entities, size_t const count) {
}
}
UTILS_NOINLINE
void FScene::removeAllEntities() noexcept {
mEntities.clear();
}
UTILS_NOINLINE
size_t FScene::getRenderableCount() const noexcept {
FEngine& engine = mEngine;

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