Compare commits

..
Author SHA1 Message Date
Sungun Park cf75b4489b feedback 2025-02-04 13:41:42 -08:00
Sungun Park 923ac98ea8 Add multiview_data for multiview information
Add a varying variable `multiview_data` for both surface and
post-processing shaders. Currently this only works as intended in
surface shader, and additional implementation to facilitate it for
post-processing will be following.

The `multiview_data` contains multiview information like whether
multiview is enabled for the current material and what the eye index is
in that case. This variable is globally available including fragment
shaders so that it can be referenced in user shaders in .material files.
Also this allows us to indirectly reference the constant variables such
as `gl_ViewID_OVR` and `gl_ViewIndex` in a platform-agnostic way.

Make the preprocessor `MATERIAL_FEATURE_LEVEL` available for both
surface and post-processing shaders, it used to be only available for
surface shader, and this will be referenced in post-processing shaders
later to support multiview for post-processing.
2025-02-03 19:48:20 -08:00
109 changed files with 789 additions and 2792 deletions
+11 -18
View File
@@ -528,7 +528,7 @@ if (FILAMENT_SUPPORTS_METAL)
endif()
# Building filamat increases build times and isn't required for web, so turn it off by default.
if (NOT WEBGL AND NOT IOS)
if (NOT WEBGL)
option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" ON)
else()
option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" OFF)
@@ -667,6 +667,10 @@ 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)
@@ -681,22 +685,12 @@ function(combine_static_libs TARGET OUTPUT DEPS)
endif()
endforeach()
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()
add_custom_command(
TARGET ${TARGET} POST_BUILD
COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES}
COMMENT "Combining ${target} dependencies into single shared library"
VERBATIM
)
endfunction()
# ==================================================================================================
@@ -767,7 +761,6 @@ 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
- matdbg: Add support for debugging ESSL 1.0 shaders
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.57.2'
implementation 'com.google.android.filament:filament-android:1.56.7'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.57.2'
pod 'Filament', '~> 1.56.7'
```
## Documentation
-12
View File
@@ -7,18 +7,6 @@ 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.2
- Support including PlatformMetal.h in C++ files.
## 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,18 +329,6 @@ 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*,
@@ -517,14 +505,6 @@ 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,
@@ -53,14 +53,6 @@ Java_com_google_android_filament_Texture_nIsTextureFormatSupported(JNIEnv*, jcla
(Texture::InternalFormat) internalFormat);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Texture_nIsTextureFormatMipmappable(JNIEnv*, jclass,
jlong nativeEngine, jint internalFormat) {
Engine *engine = (Engine *) nativeEngine;
return (jboolean) Texture::isTextureFormatMipmappable(*engine,
(Texture::InternalFormat) internalFormat);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jclass,
jlong nativeEngine) {
@@ -68,16 +60,6 @@ Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jcl
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
return (jboolean) Texture::validatePixelFormatAndType(
(Texture::InternalFormat) internalFormat,
(Texture::Format) pixelDataFormat,
(Texture::Type) pixelDataType
);
}
// Texture::Builder...
extern "C" JNIEXPORT jlong JNICALL
@@ -1271,7 +1271,7 @@ public class Engine {
* {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.</p>
*/
public void flushAndWait() {
boolean unused = flushAndWait(Fence.WAIT_FOR_EVER);
flushAndWait(Fence.WAIT_FOR_EVER);
}
/**
@@ -556,20 +556,6 @@ 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.
*/
@@ -578,14 +564,6 @@ 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.
*
@@ -942,8 +920,6 @@ 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);
@@ -976,7 +952,6 @@ 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);
@@ -653,19 +653,6 @@ public class Texture {
return nIsTextureFormatSupported(engine.getNativeObject(), format.ordinal());
}
/**
* Checks whether a given texture format is supported for mipmapping in this {@link Engine}.
* This depends on the selected backend.
*
* @param engine {@link Engine} to test the {@link InternalFormat InternalFormat} against
* @param format format to check
* @return <code>true</code> if this format is supported for texturing.
*/
public static boolean isTextureFormatMipmappable(@NonNull Engine engine,
@NonNull InternalFormat format) {
return nIsTextureFormatMipmappable(engine.getNativeObject(), format.ordinal());
}
/**
* Checks whether texture swizzling is supported in this {@link Engine}.
* This depends on the selected backend.
@@ -677,20 +664,6 @@ public class Texture {
return nIsTextureSwizzleSupported(engine.getNativeObject());
}
/**
* Checks whether a given combination of texture format, pixel data and type is valid.
*
* @param internalFormat texture format
* @param pixelDataFormat pixel data format
* @param pixelDataType pixel data type
* @return <code>true</code> if the combination is valid
*/
public static boolean validatePixelFormatAndType(@NonNull InternalFormat internalFormat,
@NonNull Format pixelDataFormat, @NonNull Type pixelDataType) {
return nValidatePixelFormatAndType(internalFormat.ordinal(), pixelDataFormat.ordinal(),
pixelDataType.ordinal());
}
/**
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
*/
@@ -1287,12 +1260,8 @@ public class Texture {
}
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
int pixelDataType);
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeBuilder);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.57.2
VERSION_NAME=1.56.7
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+39
View File
@@ -0,0 +1,39 @@
@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%
+1 -2
View File
@@ -460,8 +460,7 @@ if (APPLE OR LINUX)
spirv-cross-glsl)
endif()
# TODO: Disabling IOS test due to breakage wrt glslang update
if (APPLE AND NOT IOS)
if (APPLE)
# TODO: we should expand this test to Linux and other platforms.
list(APPEND BACKEND_TEST_SRC
test/test_RenderExternalImage.cpp)
+1 -54
View File
@@ -25,8 +25,6 @@
#include <stddef.h>
#include <stdint.h>
#include <atomic>
namespace filament::backend {
class Driver;
@@ -43,50 +41,6 @@ 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.)
@@ -144,13 +98,6 @@ public:
* - PlatformEGLAndroid
*/
bool assertNativeWindowIsValid = false;
/**
* The action to take if a Drawable cannot be acquired. If true, the
* frame is aborted instead of panic. This is only supported for:
* - PlatformMetal
*/
bool metalDisablePanicOnDrawableFailure = false;
};
Platform() noexcept;
@@ -176,7 +123,7 @@ public:
*
* @return nullptr on failure, or a pointer to the newly created driver.
*/
virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
const DriverConfig& driverConfig) noexcept = 0;
/**
@@ -23,7 +23,6 @@
#include <utils/compiler.h>
#include <utils/Invocable.h>
#include <utils/CString.h>
#include <stddef.h>
#include <stdint.h>
@@ -52,23 +51,12 @@ 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
@@ -336,45 +324,36 @@ public:
* Destroys an external texture handle and associated data.
* @param texture a pointer to the handle to destroy.
*/
virtual void destroyExternalImageTexture(ExternalTexture* UTILS_NONNULL texture) noexcept;
virtual void destroyExternalImage(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 destroyExternalImageTexture() is called.
* concrete implementation. Ownership is released when destroyExternalImage() 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 a problem with a backend doing state caching.
* binding upon return. This is to avoid 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,6 +17,7 @@
#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>
@@ -33,14 +34,12 @@ public:
PlatformCocoaGL();
~PlatformCocoaGL() noexcept override;
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
protected:
// --------------------------------------------------------------------------------------------
// Platform Interface
Driver* createDriver(void* sharedContext,
const DriverConfig& driverConfig) noexcept override;
const Platform::DriverConfig& driverConfig) noexcept override;
// Currently returns 0
int getOSVersion() const noexcept override;
@@ -60,12 +59,10 @@ protected:
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImage(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,13 +32,11 @@ public:
PlatformCocoaTouchGL();
~PlatformCocoaTouchGL() noexcept override;
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
// --------------------------------------------------------------------------------------------
// Platform Interface
Driver* createDriver(void* sharedGLContext,
const DriverConfig& driverConfig) noexcept override;
const Platform::DriverConfig& driverConfig) noexcept override;
int getOSVersion() const noexcept final { return 0; }
@@ -58,12 +56,10 @@ public:
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImage(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,11 +47,6 @@ 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
@@ -80,7 +75,8 @@ protected:
* Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation
* that supports OpenGL/OpenGL ES.
*/
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override;
Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
/**
* This returns zero. This method can be overridden to return something more useful.
@@ -122,10 +118,9 @@ protected:
void destroyFence(Fence* fence) noexcept override;
FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImage(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
@@ -193,12 +188,6 @@ 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,11 +57,6 @@ protected:
Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
/**
* Creates an ExternalImage from a EGLImageKHR
*/
ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept;
// --------------------------------------------------------------------------------------------
// OpenGLPlatform Interface
@@ -94,15 +89,6 @@ 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,
@@ -1,38 +0,0 @@
/*
* 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,17 +20,12 @@
#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();
@@ -46,22 +41,21 @@ public:
* free to decide which one to use. On mobile systems with a single GPU, implementations should
* simply return the result of MTLCreateSystemDefaultDevice();
*/
virtual void createDevice(MetalDevice& outDevice) noexcept;
virtual id<MTLDevice> createDevice() noexcept;
/**
* Create a command submission queue on the Metal device object.
*
* @param device The device which was returned from createDevice()
*/
virtual void createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept;
virtual id<MTLCommandQueue> createCommandQueue(id<MTLDevice> device) 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.
*/
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
id<MTLCommandBuffer> createAndEnqueueCommandBuffer() noexcept;
/**
* The action to take if a Drawable cannot be acquired.
@@ -71,9 +71,6 @@ 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;
};
/**
@@ -91,7 +88,6 @@ public:
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
uint32_t layerCount = 1;
bool isProtected = false;
};
@@ -307,11 +303,6 @@ public:
*/
uint32_t height;
/**
* The layerCount of the external image
*/
uint32_t layerCount;
/**
* The layer count of the external image
*/
@@ -215,14 +215,6 @@ 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,
@@ -363,7 +355,6 @@ 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)
@@ -29,7 +29,6 @@
#include <tsl/robin_map.h>
#include <atomic>
#include <cstddef>
#include <exception>
#include <mutex>
@@ -250,8 +249,8 @@ public:
if (UTILS_LIKELY(isPoolHandle(id))) {
// Truncate the age to get the debug tag
key &= ~(HANDLE_DEBUG_TAG_MASK ^ HANDLE_AGE_MASK);
writeHandleTag(key, std::move(tag));
}
writeHandleTag(key, std::move(tag));
}
private:
@@ -427,7 +426,7 @@ private:
// Below is only used when running out of space in the HandleArena
mutable utils::Mutex mLock;
tsl::robin_map<HandleBase::HandleId, void*> mOverflowMap;
std::atomic<HandleBase::HandleId> mId = 0;
HandleBase::HandleId mId = 0;
bool mUseAfterFreeCheckDisabled = false;
};
-94
View File
@@ -16,102 +16,8 @@
#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
+3 -38
View File
@@ -31,7 +31,6 @@
#include "MetalTimerQuery.h"
#include <backend/platforms/PlatformMetal.h>
#include <backend/platforms/PlatformMetal-ObjC.h>
#include <CoreVideo/CVMetalTexture.h>
#include <CoreVideo/CVPixelBuffer.h>
@@ -121,11 +120,8 @@ MetalDriver::MetalDriver(
TrackedMetalBuffer::setPlatform(platform);
ScopedAllocationTimer::setPlatform(platform);
MetalDevice device;
device.device = nil;
mPlatform.createDevice(device);
mContext->device = device.device;
FILAMENT_CHECK_POSTCONDITION(mContext->device) << "Could not obtain Metal device.";
mContext->device = mPlatform.createDevice();
assert_invariant(mContext->device);
mContext->emptyBuffer = [mContext->device newBufferWithLength:16
options:MTLResourceStorageModePrivate];
@@ -190,13 +186,7 @@ MetalDriver::MetalDriver(
[mContext->device.name containsString:@"Apple A8 GPU"] ||
[mContext->device.name containsString:@"Apple A7 GPU"];
MetalCommandQueue commandQueue;
commandQueue.commandQueue = nil;
mPlatform.createCommandQueue(device, commandQueue);
FILAMENT_CHECK_POSTCONDITION(commandQueue.commandQueue)
<< "Could not create Metal command queue.";
mContext->commandQueue = commandQueue.commandQueue;
mContext->commandQueue = mPlatform.createCommandQueue(mContext->device);
mContext->pipelineStateCache.setDevice(mContext->device);
mContext->depthStencilStateCache.setDevice(mContext->device);
mContext->samplerStateCache.setDevice(mContext->device);
@@ -523,14 +513,6 @@ 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,
@@ -765,10 +747,6 @@ 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>();
}
@@ -1240,10 +1218,6 @@ 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
@@ -1408,9 +1382,6 @@ void MetalDriver::commit(Handle<HwSwapChain> sch) {
void MetalDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
return;
}
FILAMENT_CHECK_PRECONDITION(isInRenderPass(mContext))
<< "setPushConstant must be called inside a render pass.";
assert_invariant(static_cast<size_t>(stage) < mContext->currentPushConstants.size());
@@ -1718,9 +1689,6 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
}
void MetalDriver::bindPipeline(PipelineState const& ps) {
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
return;
}
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
<< "bindPipeline() without a valid command encoder.";
DEBUG_LOG("bindPipeline(ps = { program = %d }))\n", ps.program.getId());
@@ -1876,9 +1844,6 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
}
void MetalDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
return;
}
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
<< "bindRenderPrimitive() without a valid command encoder.";
+6 -46
View File
@@ -36,42 +36,6 @@
#include <math.h>
// A wrapper around a C void* pointer that will free the memory when deallocated, unless the pointer
// is first reset.
// ReleasablePointer serves a similar purpose as std::unique_ptr, but avoids false positives with
// TSAN and Objective-C blocks.
@interface ReleasablePointer : NSObject
@property(nonatomic, readonly) void* p;
@end
@implementation ReleasablePointer {
void* _p;
}
- (id)initWithPointer:(void*)p {
self = [super init];
if (self) {
_p = p;
}
return self;
}
- (void)dealloc {
if (_p) {
free(_p);
}
}
- (void*)p {
return _p;
}
- (void)reset {
_p = nullptr;
}
@end
namespace filament {
namespace backend {
@@ -392,17 +356,15 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
};
// This callback pointer will be captured by the block. Even if the scheduled handler is never
// called, the ReleasablePointer will still ensure we don't leak memory.
// called, the unique_ptr will still ensure we don't leak memory.
uint64_t const flags = frameScheduled.flags;
ReleasablePointer* callback = [[ReleasablePointer alloc]
initWithPointer:new Callback(frameScheduled.callback, drawable, layerDrawableMutex,
context.driver, flags)];
__block auto callback = std::make_unique<Callback>(
frameScheduled.callback, drawable, layerDrawableMutex, context.driver, flags);
backend::CallbackHandler* handler = frameScheduled.handler;
MetalDriver* driver = context.driver;
[getPendingCommandBuffer(&context) addScheduledHandler:^(id<MTLCommandBuffer> cb) {
Callback* user = static_cast<Callback*>(callback.p);
[callback reset];
Callback* user = callback.release();
if (flags & SwapChain::CALLBACK_DEFAULT_USE_METAL_COMPLETION_HANDLER) {
Callback::func(user);
} else {
@@ -428,14 +390,12 @@ void MetalSwapChain::scheduleFrameCompletedCallback() {
// This callback pointer will be captured by the block. Even if the completed handler is never
// called, the unique_ptr will still ensure we don't leak memory.
ReleasablePointer* callback =
[[ReleasablePointer alloc] initWithPointer:new Callback(frameCompleted.callback)];
__block auto callback = std::make_unique<Callback>(frameCompleted.callback);
CallbackHandler* handler = frameCompleted.handler;
MetalDriver* driver = context.driver;
[getPendingCommandBuffer(&context) addCompletedHandler:^(id<MTLCommandBuffer> cb) {
Callback* user = static_cast<Callback*>(callback.p);
[callback reset];
Callback* user = callback.release();
driver->scheduleCallback(handler, user, &Callback::func);
}];
}
+7 -12
View File
@@ -15,7 +15,6 @@
*/
#include <backend/platforms/PlatformMetal.h>
#include <backend/platforms/PlatformMetal-ObjC.h>
#include "MetalDriverFactory.h"
@@ -45,13 +44,10 @@ PlatformMetal::~PlatformMetal() noexcept {
}
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure
? DrawableFailureBehavior::ABORT_FRAME
: DrawableFailureBehavior::PANIC;
return MetalDriverFactory::create(this, driverConfig);
}
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
id<MTLDevice> PlatformMetal::createDevice() noexcept {
id<MTLDevice> result;
#if !defined(FILAMENT_IOS)
@@ -76,20 +72,19 @@ void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
outDevice.device = result;
return result;
}
void PlatformMetal::createCommandQueue(
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
pImpl->mCommandQueue = [device.device newCommandQueue];
id<MTLCommandQueue> PlatformMetal::createCommandQueue(id<MTLDevice> device) noexcept {
pImpl->mCommandQueue = [device newCommandQueue];
pImpl->mCommandQueue.label = @"Filament";
outCommandQueue.commandQueue = pImpl->mCommandQueue;
return pImpl->mCommandQueue;
}
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
id<MTLCommandBuffer> PlatformMetal::createAndEnqueueCommandBuffer() noexcept {
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
[commandBuffer enqueue];
outCommandBuffer.commandBuffer = commandBuffer;
return commandBuffer;
}
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
-10
View File
@@ -14,16 +14,9 @@
* 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() {
@@ -269,9 +262,6 @@ void NoopDriver::update3DImage(Handle<HwTexture> th,
scheduleDestroy(std::move(data));
}
void NoopDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
}
void NoopDriver::setupExternalImage(void* image) {
}
+23 -44
View File
@@ -18,7 +18,6 @@
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <backend/DriverEnums.h>
@@ -26,8 +25,6 @@
#include <string_view>
#include <unordered_set>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "gl_headers.h"
@@ -53,7 +50,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 GLuint getComponentCount(ElementType type) noexcept {
constexpr inline GLuint getComponentCount(ElementType type) noexcept {
using ElementType = ElementType;
switch (type) {
case ElementType::BYTE:
@@ -93,7 +90,7 @@ constexpr GLuint getComponentCount(ElementType type) noexcept {
// Our enums to GLenum conversions
// ------------------------------------------------------------------------------------------------
constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
GLbitfield mask = 0;
if (any(flags & TargetBufferFlags::COLOR_ALL)) {
mask |= (GLbitfield)GL_COLOR_BUFFER_BIT;
@@ -107,7 +104,7 @@ constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
return mask;
}
constexpr GLenum getBufferUsage(BufferUsage usage) noexcept {
constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept {
switch (usage) {
case BufferUsage::STATIC:
return GL_STATIC_DRAW;
@@ -116,7 +113,7 @@ constexpr GLenum getBufferUsage(BufferUsage usage) noexcept {
}
}
constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept {
constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept {
switch (bindingType) {
case BufferObjectBinding::VERTEX:
return GL_ARRAY_BUFFER;
@@ -137,11 +134,11 @@ constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept
}
}
constexpr GLboolean getNormalization(bool normalized) noexcept {
constexpr inline GLboolean getNormalization(bool normalized) noexcept {
return GLboolean(normalized ? GL_TRUE : GL_FALSE);
}
constexpr GLenum getComponentType(ElementType type) noexcept {
constexpr inline GLenum getComponentType(ElementType type) noexcept {
using ElementType = ElementType;
switch (type) {
case ElementType::BYTE:
@@ -186,30 +183,12 @@ constexpr GLenum getComponentType(ElementType type) 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 {
constexpr inline GLenum getCubemapTarget(uint16_t layer) noexcept {
assert_invariant(layer <= 5);
return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
}
constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept {
constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept {
using SamplerWrapMode = SamplerWrapMode;
switch (mode) {
case SamplerWrapMode::REPEAT:
@@ -221,7 +200,7 @@ constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept {
}
}
constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
using SamplerMinFilter = SamplerMinFilter;
switch (filter) {
case SamplerMinFilter::NEAREST:
@@ -236,12 +215,12 @@ constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
}
}
constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
constexpr inline GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
return GL_NEAREST + GLenum(filter);
}
constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept {
constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept {
using BlendEquation = BlendEquation;
switch (mode) {
case BlendEquation::ADD: return GL_FUNC_ADD;
@@ -252,7 +231,7 @@ constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept {
}
}
constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
using BlendFunction = BlendFunction;
switch (mode) {
case BlendFunction::ZERO: return GL_ZERO;
@@ -269,7 +248,7 @@ constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
}
}
constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept {
constexpr inline GLenum getCompareFunc(SamplerCompareFunc func) noexcept {
switch (func) {
case SamplerCompareFunc::LE: return GL_LEQUAL;
case SamplerCompareFunc::GE: return GL_GEQUAL;
@@ -283,25 +262,25 @@ constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept {
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
constexpr GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept {
constexpr inline GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept {
return mode == SamplerCompareMode::NONE ?
GL_NONE : GL_COMPARE_REF_TO_TEXTURE;
}
constexpr GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept {
constexpr inline GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func);
}
#endif
constexpr GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
constexpr inline GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func);
}
constexpr GLenum getStencilFunc(SamplerCompareFunc func) noexcept {
constexpr inline GLenum getStencilFunc(SamplerCompareFunc func) noexcept {
return getCompareFunc(func);
}
constexpr GLenum getStencilOp(StencilOperation op) noexcept {
constexpr inline GLenum getStencilOp(StencilOperation op) noexcept {
switch (op) {
case StencilOperation::KEEP: return GL_KEEP;
case StencilOperation::ZERO: return GL_ZERO;
@@ -314,7 +293,7 @@ constexpr GLenum getStencilOp(StencilOperation op) noexcept {
}
}
constexpr GLenum getFormat(PixelDataFormat format) noexcept {
constexpr inline GLenum getFormat(PixelDataFormat format) noexcept {
using PixelDataFormat = PixelDataFormat;
switch (format) {
case PixelDataFormat::RGB: return GL_RGB;
@@ -338,7 +317,7 @@ constexpr GLenum getFormat(PixelDataFormat format) noexcept {
}
}
constexpr GLenum getType(PixelDataType type) noexcept {
constexpr inline GLenum getType(PixelDataType type) noexcept {
using PixelDataType = PixelDataType;
switch (type) {
case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE;
@@ -363,7 +342,7 @@ constexpr GLenum getType(PixelDataType type) noexcept {
}
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
using TextureSwizzle = TextureSwizzle;
switch (c) {
case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO;
@@ -376,7 +355,7 @@ constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
}
#endif
constexpr GLenum getCullingMode(CullingMode mode) noexcept {
constexpr inline GLenum getCullingMode(CullingMode mode) noexcept {
switch (mode) {
case CullingMode::NONE:
// should never happen
@@ -391,7 +370,7 @@ constexpr GLenum getCullingMode(CullingMode mode) noexcept {
}
// ES2 supported internal formats for texturing and how they map to a format/type
constexpr std::pair<GLenum, GLenum> textureFormatToFormatAndType(
constexpr inline std::pair<GLenum, GLenum> textureFormatToFormatAndType(
TextureFormat format) noexcept {
switch (format) {
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
+64 -127
View File
@@ -39,7 +39,6 @@
#include <backend/Program.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/CommandStream.h"
#include "private/backend/Dispatcher.h"
#include "private/backend/DriverApi.h"
@@ -47,11 +46,9 @@
#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>
@@ -157,8 +154,8 @@ using namespace GLUtils;
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
assert_invariant(platform);
OpenGLPlatform* const ec = platform;
@@ -225,7 +222,7 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
}
#endif
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
size_t const 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);
@@ -280,6 +277,7 @@ 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);
@@ -368,8 +366,8 @@ void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
mContext.bindSampler(unit, sampler);
}
void OpenGLDriver::setPushConstant(ShaderStage stage, uint8_t index,
PushConstantVariant value) {
void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
#if FILAMENT_ENABLE_MATDBG
@@ -378,7 +376,7 @@ void OpenGLDriver::setPushConstant(ShaderStage stage, uint8_t index,
}
#endif
Slice<std::pair<GLint, ConstantType>> constants;
utils::Slice<std::pair<GLint, ConstantType>> constants;
if (stage == ShaderStage::VERTEX) {
constants = mCurrentPushConstants->vertexConstants;
} else if (stage == ShaderStage::FRAGMENT) {
@@ -584,10 +582,6 @@ Handle<HwTexture> OpenGLDriver::createTextureViewSwizzleS() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureExternalImage2S() noexcept {
return initHandle<GLTexture>();
}
Handle<HwTexture> OpenGLDriver::createTextureExternalImageS() noexcept {
return initHandle<GLTexture>();
}
@@ -683,7 +677,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
bo->gl.buffer = malloc(byteCount);
memset(bo->gl.buffer, 0, byteCount);
} else {
bo->gl.binding = getBufferBindingType(bindingType);
bo->gl.binding = GLUtils::getBufferBindingType(bindingType);
glGenBuffers(1, &bo->gl.id);
gl.bindBuffer(bo->gl.binding, bo->gl.id);
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
@@ -760,7 +754,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
}
UTILS_NOINLINE
void OpenGLDriver::textureStorage(GLTexture* t,
void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept {
auto& gl = mContext;
@@ -896,17 +890,6 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) {
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
@@ -920,7 +903,25 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
t->gl.internalFormat = internalFormat;
t->gl.target = getTextureTargetNotExternal(target);
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;
}
if (t->samples > 1) {
// Note: we can't be here in practice because filament's user API doesn't
@@ -994,7 +995,8 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a) {
DEBUG_MARKER()
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
@@ -1056,57 +1058,6 @@ 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()
@@ -1128,16 +1079,6 @@ 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
@@ -1157,7 +1098,7 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
}
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane) {
// not relevant for the OpenGL backend
}
@@ -1473,7 +1414,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.
@@ -1673,9 +1614,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
rt->gl.samples = samples;
rt->targets = targets;
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) {
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) {
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) };
@@ -1929,7 +1870,7 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
detachStream(t);
}
if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) {
mPlatform.destroyExternalImageTexture(t->externalTexture);
mPlatform.destroyExternalImage(t->externalTexture);
} else {
glDeleteTextures(1, &t->gl.id);
}
@@ -2377,11 +2318,11 @@ bool OpenGLDriver::isStereoSupported() {
return false;
}
switch (mDriverConfig.stereoscopicType) {
case StereoscopicType::INSTANCED:
case backend::StereoscopicType::INSTANCED:
return mContext.ext.EXT_clip_cull_distance;
case StereoscopicType::MULTIVIEW:
case backend::StereoscopicType::MULTIVIEW:
return mContext.ext.OVR_multiview2;
case StereoscopicType::NONE:
case backend::StereoscopicType::NONE:
return false;
}
}
@@ -2394,7 +2335,7 @@ bool OpenGLDriver::isDepthStencilResolveSupported() {
return true;
}
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat) {
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat format) {
return true;
}
@@ -2428,12 +2369,12 @@ FeatureLevel OpenGLDriver::getFeatureLevel() {
return mContext.getFeatureLevel();
}
float2 OpenGLDriver::getClipSpaceParams() {
math::float2 OpenGLDriver::getClipSpaceParams() {
return mContext.ext.EXT_clip_control ?
// z-coordinate of virtual and physical clip-space is in [-w, 0]
float2{ 1.0f, 0.0f } :
math::float2{ 1.0f, 0.0f } :
// z-coordinate of virtual clip-space is in [-w,0], physical is in [-w, w]
float2{ 2.0f, -1.0f };
math::float2{ 2.0f, -1.0f };
}
uint8_t OpenGLDriver::getMaxDrawBuffers() {
@@ -2497,7 +2438,7 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, CString tag) {
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
@@ -2673,7 +2614,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p) {
@@ -2782,7 +2723,7 @@ void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p) {
@@ -2868,10 +2809,6 @@ void OpenGLDriver::setCompressedTextureData(GLTexture const* 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);
}
@@ -3423,8 +3360,8 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
#endif
}
void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
uint32_t offset, uint32_t size, BufferDescriptor&& p) {
void OpenGLDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
assert_invariant(!gl.isES2());
@@ -3571,13 +3508,13 @@ void OpenGLDriver::beginFrame(
}
}
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain>, CallbackHandler*,
FrameScheduledCallback&& /*callback*/, uint64_t /*flags*/) {
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
FrameScheduledCallback&& callback, uint64_t flags) {
DEBUG_MARKER()
}
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain>,
CallbackHandler*, Invocable<void()>&& /*callback*/) {
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
DEBUG_MARKER()
}
@@ -3608,9 +3545,9 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
}
void OpenGLDriver::updateDescriptorSetBuffer(
DescriptorSetHandle dsh,
descriptor_binding_t binding,
BufferObjectHandle boh,
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size) {
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
GLBufferObject* bo = boh ? handle_cast<GLBufferObject*>(boh) : nullptr;
@@ -3618,9 +3555,9 @@ void OpenGLDriver::updateDescriptorSetBuffer(
}
void OpenGLDriver::updateDescriptorSetTexture(
DescriptorSetHandle dsh,
descriptor_binding_t binding,
TextureHandle th,
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::TextureHandle th,
SamplerParams params) {
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
GLTexture* t = th ? handle_cast<GLTexture*>(th) : nullptr;
@@ -3653,7 +3590,7 @@ void OpenGLDriver::finish(int) {
UTILS_NOINLINE
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
mContext.colorMask(GL_TRUE);
@@ -3976,9 +3913,9 @@ void OpenGLDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
}
void OpenGLDriver::bindDescriptorSet(
DescriptorSetHandle dsh,
descriptor_set_t set,
DescriptorSetOffsetArray&& offsets) {
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
backend::DescriptorSetOffsetArray&& offsets) {
if (UTILS_UNLIKELY(!dsh)) {
mBoundDescriptorSets[set].dsh = dsh;
@@ -4010,7 +3947,7 @@ void OpenGLDriver::bindDescriptorSet(
}
}
void OpenGLDriver::updateDescriptors(bitset8 invalidDescriptorSets) noexcept {
void OpenGLDriver::updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept {
assert_invariant(mBoundProgram);
auto const offsetOnly = mInvalidDescriptorSetBindingOffsets & ~mInvalidDescriptorSetBindings;
invalidDescriptorSets.forEachSetBit([this, offsetOnly,
@@ -4122,7 +4059,7 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph,
}
}
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 workGroupCount) {
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
DEBUG_MARKER()
getShaderCompilerService().tick();
+21 -30
View File
@@ -19,7 +19,6 @@
#include "DriverBase.h"
#include "OpenGLContext.h"
#include "OpenGLDriverBase.h"
#include "OpenGLTimerQuery.h"
#include "GLBufferObject.h"
#include "GLDescriptorSet.h"
@@ -27,10 +26,11 @@
#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,7 +41,6 @@
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <math/vec4.h>
@@ -75,14 +74,14 @@ class OpenGLProgram;
class TimerQueryFactoryInterface;
struct PushConstantBundle;
class OpenGLDriver final : public OpenGLDriverBase {
class OpenGLDriver final : public DriverBase {
inline explicit OpenGLDriver(OpenGLPlatform* platform,
const Platform::DriverConfig& driverConfig) noexcept;
~OpenGLDriver() noexcept override;
Dispatcher getDispatcher() const noexcept override;
~OpenGLDriver() noexcept final;
Dispatcher getDispatcher() const noexcept final;
public:
static OpenGLDriver* create(OpenGLPlatform* platform, void* sharedGLContext,
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept;
class DebugMarker {
@@ -185,7 +184,7 @@ public:
std::condition_variable cond;
FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED };
};
std::shared_ptr<State> state{ std::make_shared<State>() };
std::shared_ptr<State> state{ std::make_shared<GLFence::State>() };
};
OpenGLDriver(OpenGLDriver const&) = delete;
@@ -204,21 +203,13 @@ private:
return mShaderCompilerService;
}
ShaderModel getShaderModel() const noexcept override;
ShaderLanguage getShaderLanguage() const noexcept override;
ShaderModel getShaderModel() const noexcept final;
ShaderLanguage getShaderLanguage() const noexcept final;
/*
* OpenGLDriver interface
* Driver 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;
@@ -245,21 +236,21 @@ private:
}
template<typename D, typename B, typename ... ARGS>
std::enable_if_t<std::is_base_of_v<B, D>, D>*
typename std::enable_if<std::is_base_of<B, D>::value, D>::type*
construct(Handle<B> const& handle, ARGS&& ... args) {
return mHandleAllocator.destroyAndConstruct<D, B>(handle, std::forward<ARGS>(args) ...);
}
template<typename B, typename D,
typename = std::enable_if_t<std::is_base_of_v<B, D>, D>>
typename = typename std::enable_if<std::is_base_of<B, D>::value, D>::type>
void destruct(Handle<B>& handle, D const* p) noexcept {
return mHandleAllocator.deallocate(handle, p);
}
template<typename Dp, typename B>
std::enable_if_t<
typename std::enable_if_t<
std::is_pointer_v<Dp> &&
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
handle_cast(Handle<B>& handle) {
return mHandleAllocator.handle_cast<Dp, B>(handle);
}
@@ -270,9 +261,9 @@ private:
}
template<typename Dp, typename B>
std::enable_if_t<
inline typename std::enable_if_t<
std::is_pointer_v<Dp> &&
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
handle_cast(Handle<B> const& handle) {
return mHandleAllocator.handle_cast<Dp, B>(handle);
}
@@ -297,13 +288,13 @@ private:
void setStencilState(StencilState ss) noexcept;
void setTextureData(GLTexture const* t,
void setTextureData(GLTexture* 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 const* t,
void setCompressedTextureData(GLTexture* t,
uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
@@ -312,7 +303,7 @@ private:
void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width,
uint32_t height, uint8_t samples) const noexcept;
void textureStorage(GLTexture* t, uint32_t width, uint32_t height,
void textureStorage(OpenGLDriver::GLTexture* t, uint32_t width, uint32_t height,
uint32_t depth, bool useProtectedMemory) noexcept;
/* State tracking GL wrappers... */
@@ -344,9 +335,9 @@ private:
void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept;
struct {
DescriptorSetHandle dsh;
backend::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;
@@ -1,37 +0,0 @@
/*
* 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
+3 -38
View File
@@ -16,7 +16,6 @@
#include <backend/platforms/OpenGLPlatform.h>
#include "OpenGLDriverBase.h"
#include "OpenGLDriverFactory.h"
#include <backend/AcquiredImage.h>
@@ -24,45 +23,21 @@
#include <backend/Platform.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <utils/CString.h>
#include <utils/Invocable.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 DriverConfig& driverConfig) {
void* sharedContext, const Platform::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);
@@ -146,24 +121,14 @@ OpenGLPlatform::ExternalTexture* OpenGLPlatform::createExternalImageTexture() no
return nullptr;
}
void OpenGLPlatform::destroyExternalImageTexture(
void OpenGLPlatform::destroyExternalImage(
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 {
@@ -54,15 +54,8 @@ 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)
@@ -316,12 +309,17 @@ 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::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
void PlatformCocoaGL::destroyExternalImage(ExternalTexture* texture) noexcept {
auto* p = static_cast<CocoaExternalImage*>(texture);
delete p;
}
@@ -346,36 +344,6 @@ 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,15 +47,8 @@ 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) {
}
@@ -205,10 +198,13 @@ 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::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
void PlatformCocoaTouchGL::destroyExternalImage(ExternalTexture* texture) noexcept {
auto* p = static_cast<CocoaTouchExternalImage*>(texture);
delete p;
}
@@ -233,35 +229,4 @@ 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,9 +117,7 @@ bool PlatformEGL::isOpenGL() const noexcept {
return false;
}
PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default;
Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept {
Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept {
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
@@ -297,7 +295,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
clearGlError();
// success!!
return createDefaultDriver(this, sharedContext, driverConfig);
return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig);
error:
// if we're here, we've failed
@@ -551,7 +549,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
return sc;
}
void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept {
void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
if (sc->sur != EGL_NO_SURFACE) {
@@ -564,7 +562,7 @@ void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept {
}
}
bool PlatformEGL::isSwapChainProtected(SwapChain* swapChain) noexcept {
bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
@@ -585,10 +583,10 @@ bool PlatformEGL::makeCurrent(ContextType type,
return success == EGL_TRUE ? true : false;
}
void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
SwapChain* readSwapChain,
Invocable<void()> preContextChange,
Invocable<void(size_t index)> postContextChange) noexcept {
void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept {
assert_invariant(drawSwapChain);
assert_invariant(readSwapChain);
@@ -647,7 +645,7 @@ void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
}
}
void PlatformEGL::commit(SwapChain* swapChain) noexcept {
void PlatformEGL::commit(Platform::SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
if (sc->sur != EGL_NO_SURFACE) {
@@ -670,7 +668,7 @@ Platform::Fence* PlatformEGL::createFence() noexcept {
return f;
}
void PlatformEGL::destroyFence(Fence* fence) noexcept {
void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept {
#ifdef EGL_KHR_reusable_sync
EGLSyncKHR sync = (EGLSyncKHR) fence;
if (sync != EGL_NO_SYNC_KHR) {
@@ -680,7 +678,7 @@ void PlatformEGL::destroyFence(Fence* fence) noexcept {
}
FenceStatus PlatformEGL::waitFence(
Fence* fence, uint64_t timeout) noexcept {
Platform::Fence* fence, uint64_t timeout) noexcept {
#ifdef EGL_KHR_reusable_sync
EGLSyncKHR sync = (EGLSyncKHR) fence;
if (sync != EGL_NO_SYNC_KHR) {
@@ -701,10 +699,16 @@ 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::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept {
glDeleteTextures(1, &texture->id);
delete texture;
}
@@ -724,18 +728,6 @@ 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 {
@@ -746,7 +738,7 @@ void PlatformEGL::initializeGlExtensions() noexcept {
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
}
EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept {
EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept {
switch (type) {
case ContextType::NONE:
return EGL_NO_CONTEXT;
@@ -231,26 +231,6 @@ 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) {
+2 -13
View File
@@ -163,24 +163,13 @@ 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,
};
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,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
};
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;
+1 -17
View File
@@ -552,15 +552,6 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
texture.inc();
}
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
backend::SamplerType target, backend::TextureFormat format,
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) {
@@ -579,7 +570,7 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
1, metadata.width, metadata.height, usage, mStagePool);
texture.inc();
}
@@ -801,10 +792,6 @@ 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>();
}
@@ -1184,9 +1171,6 @@ 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) {
}
+4 -12
View File
@@ -128,15 +128,6 @@ 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) {
@@ -283,21 +274,22 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
height = extent.height;
mProtected = swapchain->isProtected();
VulkanAttachment color = createSwapchainAttachment(swapchain->getCurrentColor());
VulkanAttachment color = {};
color.texture = 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 = createSwapchainAttachment(swapchain->getDepth());
VulkanAttachment depth = {};
depth.texture = swapchain->getDepth();
mInfo->attachments.push_back(depth);
mInfo->depthIndex = 1;
@@ -218,6 +218,12 @@ 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;
@@ -40,8 +40,6 @@ 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);
@@ -78,18 +76,17 @@ 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, bundle.layerCount, colorUsage,
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, 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, bundle.layerCount, depthUsage,
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, depthUsage,
mStagePool);
mExtent = bundle.extent;
mLayerCount = bundle.layerCount;
}
void VulkanSwapChain::present() {
@@ -100,7 +97,7 @@ void VulkanSwapChain::present() {
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = mLayerCount,
.layerCount = 1,
};
mColors[mCurrentSwapIndex]->transitionLayout(&commands, subresources, VulkanLayout::PRESENT);
}
@@ -96,7 +96,6 @@ 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;
+12 -31
View File
@@ -144,16 +144,6 @@ 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,
@@ -175,12 +165,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, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
: HwTexture(getSamplerTypeFromDepth(depth), 1, samples, width, height, depth, TextureFormat::UNUSED,
uint32_t height, TextureUsage tusage, VulkanStagePool& stagePool)
: HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED,
tusage),
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D),
/*mipLevels=*/1, getLayerCountFromDepth(depth), getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
mState->mTextureImage = image;
mState->mTextureImageMemory = memory;
mPrimaryViewRange = mState->mFullViewRange;
@@ -193,6 +183,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h,
uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
: HwTexture(target, levels, samples, w, h, depth, tformat, tusage),
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
allocator, commands, stagePool, fvkutils::getVkFormat(tformat),
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
@@ -208,20 +199,11 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = 0,
};
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) {
if (target == SamplerType::SAMPLER_CUBEMAP) {
imageInfo.arrayLayers = 6;
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
} else if (target == SamplerType::SAMPLER_2D_ARRAY) {
}
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:
@@ -265,9 +247,9 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
// Validate that the format is actually sampleable.
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, mState->mVkFormat, &props);
vkGetPhysicalDeviceFormatProperties(physicalDevice, state->mVkFormat, &props);
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << state->mVkFormat << " is not "
"sampleable with optimal tiling." << utils::io::endl;
}
#endif
@@ -649,16 +631,15 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
if (hasTransitions) {
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
<< range.levelCount << ")" << " from=" << oldLayout << " to=" << newLayout
<< " format=" << mState->mVkFormat << " depth="
<< fvkutils::isVkDepthFormat(mState->mVkFormat)
<< " format=" << state->mVkFormat << " depth=" << isVkDepthFormat(state->mVkFormat)
<< " slice-by-slice=" << transitionSliceBySlice << utils::io::endl;
#endif
} else {
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
<< range.levelCount << ")" << " to=" << newLayout
<< " is skipped because of no change in layout" << utils::io::endl;
+1 -1
View File
@@ -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, uint32_t depth,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height,
TextureUsage tusage, VulkanStagePool& stagePool);
// Constructor for creating a texture view for wrt specific mip range
@@ -18,7 +18,6 @@
#include <backend/DriverEnums.h>
#include "vulkan/VulkanContext.h"
#include "vulkan/platform/VulkanPlatformSwapChainImpl.h"
#include "vulkan/VulkanConstants.h"
#include "vulkan/VulkanDriver.h"
@@ -45,7 +44,7 @@ namespace filament::backend {
namespace {
constexpr uint32_t INVALID_VK_INDEX = 0xFFFFFFFF;
constexpr uint32_t const INVALID_VK_INDEX = 0xFFFFFFFF;
using ExtensionSet = VulkanPlatform::ExtensionSet;
@@ -56,25 +55,25 @@ inline bool setContains(ExtensionSet const& set, utils::CString const& extension
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
// These strings need to be allocated outside a function stack
const std::string_view DESIRED_LAYERS[] = {
"VK_LAYER_KHRONOS_validation",
"VK_LAYER_KHRONOS_validation",
#if FVK_ENABLED(FVK_DEBUG_DUMP_API)
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_LUNARG_api_dump",
#endif
#if defined(ENABLE_RENDERDOC)
"VK_LAYER_RENDERDOC_Capture",
"VK_LAYER_RENDERDOC_Capture",
#endif
};
FixedCapacityVector<const char*> getEnabledLayers() {
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
FixedCapacityVector<VkLayerProperties> const availableLayers
= fvkutils::enumerate(vkEnumerateInstanceLayerProperties);
const FixedCapacityVector<VkLayerProperties> availableLayers
= filament::backend::enumerate(vkEnumerateInstanceLayerProperties);
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
for (auto const& desired: DESIRED_LAYERS) {
for (VkLayerProperties const& layer: availableLayers) {
std::string_view const availableLayer(layer.layerName);
for (const VkLayerProperties& layer: availableLayers) {
const std::string_view availableLayer(layer.layerName);
if (availableLayer == desired) {
enabledLayers.push_back(desired.data());
break;
@@ -85,13 +84,6 @@ 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) {
@@ -100,8 +92,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;
@@ -127,13 +119,13 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
// Since we don't have any vendor-specific workarounds yet, there's no need to make this
// mapping in code. The "deviceName" string informally reveals the marketing name for the
// GPU. (e.g., Quadro)
uint32_t const driverVersion = deviceProperties.driverVersion;
uint32_t const vendorID = deviceProperties.vendorID;
uint32_t const deviceID = deviceProperties.deviceID;
int const major = VK_VERSION_MAJOR(deviceProperties.apiVersion);
int const minor = VK_VERSION_MINOR(deviceProperties.apiVersion);
const uint32_t driverVersion = deviceProperties.driverVersion;
const uint32_t vendorID = deviceProperties.vendorID;
const uint32_t deviceID = deviceProperties.deviceID;
const int major = VK_VERSION_MAJOR(deviceProperties.apiVersion);
const int minor = VK_VERSION_MINOR(deviceProperties.apiVersion);
FixedCapacityVector<VkPhysicalDevice> const physicalDevices
const FixedCapacityVector<VkPhysicalDevice> physicalDevices
= fvkutils::enumerate(vkEnumeratePhysicalDevices, instance);
FVK_LOGI << "Selected physical device '" << deviceProperties.deviceName << "' from "
@@ -148,10 +140,10 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
void printDepthFormats(VkPhysicalDevice device) {
// For diagnostic purposes, print useful information about available depth formats.
// Note that Vulkan is more constrained than OpenGL ES 3.1 in this area.
constexpr VkFormatFeatureFlags required =
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
FVK_LOGI << "Sampleable depth formats: ";
for (VkFormat format : fvkutils::ALL_VK_FORMATS) {
for (VkFormat format : ALL_VK_FORMATS) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(device, format, &props);
if ((props.optimalTilingFeatures & required) == required) {
@@ -168,13 +160,11 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts =
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
// Request these if available.
// Request these if available.
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
#endif
#if defined(__APPLE__)
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
@@ -184,8 +174,8 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts =
FixedCapacityVector<VkExtensionProperties> const availableExts =
fvkutils::enumerate(vkEnumerateInstanceExtensionProperties,
static_cast<char const*>(nullptr) /* pLayerName */);
for (auto const& extension: availableExts) {
utils::CString name { extension.extensionName };
for (auto const& extProps: availableExts) {
utils::CString name { extProps.extensionName };
// To workaround an Adreno bug where the extension name could be of 0 length.
if (name.size() == 0) {
@@ -202,24 +192,22 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts =
ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
ExtensionSet const TARGET_EXTS = {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
#endif
// We only support external image for Android for now, but nothing bars us from
// supporting other platforms.
// 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,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
#endif
// MoltenVk is the only non-conformant implementation we're interested in.
#if defined(__APPLE__)
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
#endif
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME,
VK_KHR_MULTIVIEW_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
#endif
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME,
VK_KHR_MULTIVIEW_EXTENSION_NAME,
};
ExtensionSet exts;
// Identify supported physical device extensions
@@ -242,19 +230,8 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
}
VkInstance createInstance(ExtensionSet const& requiredExts) {
// Create the Vulkan instance.
VkApplicationInfo appInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pEngineName = "Filament",
.apiVersion =
VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0),
};
VkInstance instance;
VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &appInfo,
};
VkInstanceCreateInfo instanceCreateInfo = {};
bool validationFeaturesSupported = false;
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -262,7 +239,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
= fvkutils::enumerate(vkEnumerateInstanceExtensionProperties,
= filament::backend::enumerate(vkEnumerateInstanceExtensionProperties,
"VK_LAYER_KHRONOS_validation");
for (auto const& extProps: availableValidationExts) {
if (!strcmp(extProps.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) {
@@ -284,10 +261,10 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
}
#endif // FVK_ENABLED(FVK_DEBUG_VALIDATION)
// The Platform class can require 1 or 2 instance extensions, plus we'll request at most 6
// instance extensions here in the common code. So that's a max of 8.
constexpr uint32_t MAX_INSTANCE_EXTENSION_COUNT = 8;
char const* ppEnabledExtensions[MAX_INSTANCE_EXTENSION_COUNT];
// The Platform class can require 1 or 2 instance extensions, plus we'll request at most 5
// instance extensions here in the common code. So that's a max of 7.
static constexpr uint32_t MAX_INSTANCE_EXTENSION_COUNT = 8;
const char* ppEnabledExtensions[MAX_INSTANCE_EXTENSION_COUNT];
uint32_t enabledExtensionCount = 0;
if (validationFeaturesSupported) {
@@ -299,24 +276,30 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
ppEnabledExtensions[enabledExtensionCount++] = requiredExt.data();
}
// Create the Vulkan instance.
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
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;
if (setContains(requiredExts, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}
// Validation features
VkValidationFeaturesEXT features = {};
VkValidationFeatureEnableEXT enables[] = {
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
};
VkValidationFeaturesEXT features = {
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]),
.pEnabledValidationFeatures = enables,
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
};
if (validationFeaturesSupported) {
chainStruct(&instanceCreateInfo, &features);
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
features.pEnabledValidationFeatures = enables;
instanceCreateInfo.pNext = &features;
}
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
@@ -327,13 +310,11 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
bool requestImageView2DOn3DImage) {
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions) {
VkDevice device;
float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
};
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
const float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {};
FixedCapacityVector<const char*> requestExtensions;
requestExtensions.reserve(deviceExtensions.size() + 1);
@@ -342,17 +323,18 @@ 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,
.queueFamilyIndex = graphicsQueueFamilyIndex,
.queueCount = 1,
.pQueuePriorities = &queuePriority[0],
};
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
deviceQueueCreateInfo[0].queueCount = 1;
deviceQueueCreateInfo[0].pQueuePriorities = &queuePriority[0];
// Protected queue
deviceQueueCreateInfo[1] = deviceQueueCreateInfo[0];
deviceQueueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo[1].flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
deviceQueueCreateInfo[1].queueFamilyIndex = protectedGraphicsQueueFamilyIndex;
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;
@@ -360,46 +342,53 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
// We could simply enable all supported features, but since that may have performance
// consequences let's just enable the features we need.
VkPhysicalDeviceFeatures enabledFeatures{
.depthClamp = features.features.depthClamp,
.samplerAnisotropy = features.features.samplerAnisotropy,
.textureCompressionETC2 = features.features.textureCompressionETC2,
.textureCompressionBC = features.features.textureCompressionBC,
.shaderClipDistance = features.features.shaderClipDistance,
.depthClamp = features.features.depthClamp,
.samplerAnisotropy = features.features.samplerAnisotropy,
.textureCompressionETC2 = features.features.textureCompressionETC2,
.textureCompressionBC = features.features.textureCompressionBC,
.shaderClipDistance = features.features.shaderClipDistance,
};
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
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,
.imageViewFormatSwizzle = VK_TRUE,
.imageView2DOn3DImage = requestImageView2DOn3DImage ? VK_TRUE : VK_FALSE,
.mutableComparisonSamplers = VK_TRUE,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
.pNext = nullptr,
.imageViewFormatSwizzle = VK_TRUE,
.mutableComparisonSamplers = VK_TRUE,
};
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
chainStruct(&deviceCreateInfo, &portability);
portability.pNext = pNext;
pNext = &portability;
}
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.pNext = nullptr,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE
};
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
chainStruct(&deviceCreateInfo, &multiview);
multiview.pNext = pNext;
pNext = &multiview;
}
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
.protectedMemory = VK_TRUE,
};
if (hasProtectedQueue) {
// Enable protected memory, if requested.
chainStruct(&deviceCreateInfo, &protectedMemory);
protectedMemory.protectedMemory = VK_TRUE;
protectedMemory.pNext = pNext;
pNext = &protectedMemory;
}
deviceCreateInfo.pNext = pNext;
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
@@ -410,8 +399,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
// This method is used to enable/disable extensions based on external factors (i.e.
// driver/device workarounds).
std::tuple<ExtensionSet, ExtensionSet> pruneExtensions(VkPhysicalDevice device,
Platform::DriverConfig const& driverConfig, ExtensionSet const& instExts,
ExtensionSet const& deviceExts) noexcept {
ExtensionSet const& instExts, ExtensionSet const& deviceExts) {
ExtensionSet newInstExts = instExts;
ExtensionSet newDeviceExts = deviceExts;
@@ -431,10 +419,6 @@ std::tuple<ExtensionSet, ExtensionSet> pruneExtensions(VkPhysicalDevice device,
}
#endif
if (driverConfig.stereoscopicType != StereoscopicType::MULTIVIEW) {
newDeviceExts.erase(VK_KHR_MULTIVIEW_EXTENSION_NAME);
}
return std::tuple(newInstExts, newDeviceExts);
}
@@ -468,17 +452,22 @@ uint32_t identifyGraphicsQueueFamilyIndex(VkPhysicalDevice physicalDevice, VkQue
// Enum based on:
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceType.html
inline int deviceTypeOrder(VkPhysicalDeviceType deviceType) {
constexpr std::array<VkPhysicalDeviceType, 5> TYPES = {
VK_PHYSICAL_DEVICE_TYPE_OTHER,
VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU,
VK_PHYSICAL_DEVICE_TYPE_CPU,
VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
};
if (auto itr = std::find(TYPES.begin(), TYPES.end(), deviceType); itr != TYPES.end()) {
return std::distance(TYPES.begin(), itr);
switch (deviceType) {
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
return 5;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
return 4;
case VK_PHYSICAL_DEVICE_TYPE_CPU:
return 3;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
return 2;
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
return 1;
default:
FVK_LOGW << "deviceTypeOrder: Unexpected deviceType: " << deviceType
<< utils::io::endl;
return -1;
}
return -1;
}
VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
@@ -512,7 +501,7 @@ 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;
}
@@ -521,19 +510,20 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
FixedCapacityVector<VkExtensionProperties> const extensions
= fvkutils::enumerate(vkEnumerateDeviceExtensionProperties,
candidateDevice, static_cast<char const*>(nullptr) /* pLayerName */);
bool const supportsSwapchain =
std::any_of(extensions.begin(), extensions.end(), [](auto const& ext) {
return !strcmp(ext.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
});
bool supportsSwapchain = false;
for (auto const& extension: extensions) {
if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
supportsSwapchain = true;
break;
}
}
if (!supportsSwapchain) {
continue;
}
deviceList[deviceInd] = {
.device = candidateDevice,
.deviceType = targetDeviceProperties.deviceType,
.index = (int8_t) deviceInd,
.name = targetDeviceProperties.deviceName,
};
deviceList[deviceInd].device = candidateDevice;
deviceList[deviceInd].deviceType = targetDeviceProperties.deviceType;
deviceList[deviceInd].index = deviceInd;
deviceList[deviceInd].name = targetDeviceProperties.deviceName;
}
FILAMENT_CHECK_PRECONDITION(gpuPreference.index < static_cast<int32_t>(deviceList.size()))
@@ -574,7 +564,7 @@ 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.
constexpr VkFormat formats[] = {
VkFormat const formats[] = {
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_X8_D24_UNORM_PACK32,
@@ -596,7 +586,7 @@ fvkutils::VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device
fvkutils::VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) {
std::vector<VkFormat> selectedFormats;
constexpr VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
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 : fvkutils::ALL_VK_FORMATS) {
if (fvkutils::isVkDepthFormat(format)) {
@@ -656,7 +646,7 @@ void VulkanPlatform::terminate() {
// This is the main entry point for context creation.
Driver* VulkanPlatform::createDriver(void* sharedContext,
Platform::DriverConfig const& driverConfig) noexcept {
const Platform::DriverConfig& driverConfig) noexcept {
// Load Vulkan entry points.
FILAMENT_CHECK_POSTCONDITION(bluevk::initialize()) << "BlueVK is unable to load entry points.";
@@ -684,6 +674,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
}
VulkanContext context;
ExtensionSet instExts;
// If using a shared context, we do not assume any extensions.
if (!mImpl->mSharedContext) {
@@ -708,9 +699,9 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
instExts.merge(getRequiredInstanceExtensions());
}
if (mImpl->mInstance == VK_NULL_HANDLE) {
mImpl->mInstance = createInstance(instExts);
}
mImpl->mInstance
= mImpl->mInstance == VK_NULL_HANDLE ? createInstance(instExts) : mImpl->mInstance;
assert_invariant(mImpl->mInstance != VK_NULL_HANDLE);
bluevk::bindInstance(mImpl->mInstance);
@@ -720,9 +711,9 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
FILAMENT_CHECK_PRECONDITION(!(hasGPUPreference && sharedContext))
<< "Cannot both share context and indicate GPU preference";
if (mImpl->mPhysicalDevice == VK_NULL_HANDLE) {
mImpl->mPhysicalDevice = selectPhysicalDevice(mImpl->mInstance, pref);
}
mImpl->mPhysicalDevice = mImpl->mPhysicalDevice == VK_NULL_HANDLE
? selectPhysicalDevice(mImpl->mInstance, pref)
: mImpl->mPhysicalDevice;
assert_invariant(mImpl->mPhysicalDevice != VK_NULL_HANDLE);
printDeviceInfo(mImpl->mInstance, mImpl->mPhysicalDevice);
@@ -730,15 +721,14 @@ 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,
};
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
// We know we need to allocate the protected version of the VK objects
context.mProtectedMemorySupported =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
protectedMemoryProperties.pNext = context.mPhysicalDeviceProperties.pNext;
context.mPhysicalDeviceProperties.pNext = &protectedMemoryProperties;
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
@@ -746,103 +736,91 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
vkGetPhysicalDeviceFeatures2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceFeatures);
vkGetPhysicalDeviceMemoryProperties(mImpl->mPhysicalDevice, &context.mMemoryProperties);
if (mImpl->mGraphicsQueueFamilyIndex == INVALID_VK_INDEX) {
mImpl->mGraphicsQueueFamilyIndex =
identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice, VK_QUEUE_GRAPHICS_BIT);
mImpl->mGraphicsQueueFamilyIndex
= mImpl->mGraphicsQueueFamilyIndex == INVALID_VK_INDEX
? 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 =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
if (context.mProtectedMemorySupported) {
mImpl->mProtectedGraphicsQueueFamilyIndex
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
assert_invariant(mImpl->mProtectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
}
// Only enable shaderClipDistance if we are doing instanced stereoscopic rendering.
if (context.mPhysicalDeviceFeatures.features.shaderClipDistance == VK_TRUE
&& driverConfig.stereoscopicType != StereoscopicType::INSTANCED) {
context.mPhysicalDeviceFeatures.features.shaderClipDistance = VK_FALSE;
}
// At this point, we should have a family index that points to a family that has > 0 queues for
// graphics. In which case, we will allocate one queue for all of Filament (and assumes at least
// one has been allocated by the client if context was shared). If the index of the target queue
// within the family hasn't been provided by the client, we assume it to be 0.
if (mImpl->mGraphicsQueueIndex == INVALID_VK_INDEX) {
mImpl->mGraphicsQueueIndex = 0;
}
mImpl->mGraphicsQueueIndex
= mImpl->mGraphicsQueueIndex == INVALID_VK_INDEX ? 0 : mImpl->mGraphicsQueueIndex;
if (context.mProtectedMemorySupported) {
mImpl->mProtectedGraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(
mImpl->mPhysicalDevice, (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
// Applying the same logic to the protected queue index (Not sure about shared context and
// protection)
if (mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX) {
mImpl->mProtectedGraphicsQueueIndex = 0;
}
}
// Only enable shaderClipDistance if we are doing instanced stereoscopic rendering.
if (driverConfig.stereoscopicType != StereoscopicType::INSTANCED) {
context.mPhysicalDeviceFeatures.features.shaderClipDistance = VK_FALSE;
}
// 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;
ExtensionSet deviceExts;
// If using a shared context, we do not assume any extensions.
if (!mImpl->mSharedContext) {
deviceExts = getDeviceExtensions(mImpl->mPhysicalDevice);
auto [prunedInstExts, prunedDeviceExts] =
pruneExtensions(mImpl->mPhysicalDevice, driverConfig, instExts, deviceExts);
auto [prunedInstExts, prunedDeviceExts]
= pruneExtensions(mImpl->mPhysicalDevice, instExts, deviceExts);
instExts = prunedInstExts;
deviceExts = prunedDeviceExts;
if (driverConfig.stereoscopicType != StereoscopicType::MULTIVIEW) {
deviceExts.erase(VK_KHR_MULTIVIEW_EXTENSION_NAME);
}
}
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;
}
if (mImpl->mDevice == VK_NULL_HANDLE) {
mImpl->mDevice =
createLogicalDevice(mImpl->mPhysicalDevice, context.mPhysicalDeviceFeatures,
mImpl->mGraphicsQueueFamilyIndex, mImpl->mProtectedGraphicsQueueFamilyIndex,
deviceExts, requestPortabilitySubsetImageView2DOn3DImage);
}
mImpl->mDevice
= mImpl->mDevice == VK_NULL_HANDLE ? createLogicalDevice(mImpl->mPhysicalDevice,
context.mPhysicalDeviceFeatures, mImpl->mGraphicsQueueFamilyIndex,
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts)
: mImpl->mDevice;
assert_invariant(mImpl->mDevice != VK_NULL_HANDLE);
assert_invariant(mImpl->mGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
assert_invariant(mImpl->mGraphicsQueueIndex != INVALID_VK_INDEX);
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,
&mImpl->mGraphicsQueue);
assert_invariant(mImpl->mGraphicsQueue != VK_NULL_HANDLE);
if (context.mProtectedMemorySupported) {
assert_invariant(mImpl->mProtectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
assert_invariant(mImpl->mProtectedGraphicsQueueIndex != INVALID_VK_INDEX);
VkDeviceQueueInfo2 info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2,
.flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT,
.queueFamilyIndex = mImpl->mProtectedGraphicsQueueFamilyIndex,
.queueIndex = mImpl->mProtectedGraphicsQueueIndex,
};
VkDeviceQueueInfo2 info = {};
info.queueFamilyIndex = mImpl->mProtectedGraphicsQueueFamilyIndex;
info.queueIndex = mImpl->mProtectedGraphicsQueueIndex;
info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
info.flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
vkGetDeviceQueue2(mImpl->mDevice, &info, &mImpl->mProtectedGraphicsQueue);
assert_invariant(mImpl->mProtectedGraphicsQueue != VK_NULL_HANDLE);
}
// Store the extension support in the context
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;
}
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);
// Check the availability of lazily allocated memory
context.mLazilyAllocatedMemorySupported = false;
for (uint32_t i = 0, typeCount = context.mMemoryProperties.memoryTypeCount; i < typeCount;
++i) {
VkMemoryType const type = context.mMemoryProperties.memoryTypes[i];
if (type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
context.mLazilyAllocatedMemorySupported = true;
assert_invariant(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
break;
{
context.mLazilyAllocatedMemorySupported = false;
const uint32_t typeCount = context.mMemoryProperties.memoryTypeCount;
for(uint32_t i = 0; i < typeCount; ++i) {
const VkMemoryType type = context.mMemoryProperties.memoryTypes[i];
if (type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
context.mLazilyAllocatedMemorySupported = true;
assert_invariant(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
break;
}
}
}
+1 -1
View File
@@ -214,7 +214,7 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange&
case filament::backend::VulkanLayout::VALUE: { \
out << #VALUE; \
out << " [" \
<< filament::backend::fvkutils::getVkLayout( \
<< filament::backend::imgutil::getVkLayout( \
filament::backend::VulkanLayout::VALUE) \
<< "]"; \
break; \
-21
View File
@@ -17,7 +17,6 @@
#ifndef TNT_FILAMENT_ENGINE_H
#define TNT_FILAMENT_ENGINE_H
#include <filament/FilamentAPI.h>
#include <backend/DriverEnums.h>
@@ -33,7 +32,6 @@
#include <stdint.h>
#include <stddef.h>
namespace utils {
class Entity;
class EntityManager;
@@ -42,10 +40,6 @@ class JobSystem;
namespace filament {
namespace backend {
class Driver;
} // backend
class BufferObject;
class Camera;
class ColorGrading;
@@ -189,7 +183,6 @@ 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
@@ -317,15 +310,6 @@ public:
*/
size_t metalUploadBufferSizeBytes = 512 * 1024;
/**
* The action to take if a Drawable cannot be acquired.
*
* Each frame rendered requires a CAMetalDrawable texture, which is
* presented on-screen at the completion of each frame. These are
* limited and provided round-robin style by the system.
*/
bool metalDisablePanicOnDrawableFailure = false;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
@@ -598,11 +582,6 @@ 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.
+9 -20
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 const name, T const& value) {
void setParameter(StringLiteral 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 const name, const T* UTILS_NONNULL values, size_t const count) {
void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t 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 const count) {
const T* UTILS_NONNULL values, size_t 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 const name,
void setParameter(StringLiteral 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 const name, RgbType const type, math::float3 const color) {
void setParameter(StringLiteral name, RgbType type, math::float3 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 const type, math::float3 const color) {
void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 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 const name, RgbaType const type, math::float4 const color) {
void setParameter(StringLiteral name, RgbaType type, math::float4 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 const type, math::float4 const color) {
void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 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 const name) const {
T getParameter(StringLiteral name) const {
return getParameter<T>(name.data, name.size);
}
@@ -376,22 +376,11 @@ 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,11 +141,6 @@ 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.
+22 -52
View File
@@ -23,7 +23,6 @@
#include <backend/DriverEnums.h>
#include <backend/PixelBufferDescriptor.h>
#include <backend/Platform.h>
#include <utils/compiler.h>
@@ -71,7 +70,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI {
struct BuilderDetails;
public:
static constexpr size_t BASE_LEVEL = 0;
static constexpr const size_t BASE_LEVEL = 0;
//! Face offsets for all faces of a cubemap
struct FaceOffsets;
@@ -85,26 +84,19 @@ 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 a backend supports mipmapping of a particular format. */
static bool isTextureFormatMipmappable(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,
size_t stride, size_t height, size_t alignment) noexcept;
/** @return Whether a combination of texture format, pixel format and type is valid. */
static bool validatePixelFormatAndType(InternalFormat internalFormat, Format format, Type type) noexcept;
/**
* Options for environment prefiltering into reflection map
@@ -225,18 +217,6 @@ 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.
*
@@ -281,6 +261,18 @@ public:
*/
Builder& import(intptr_t id) noexcept;
/**
* Creates an external texture. The content must be set using setExternalImage().
* The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally
* YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not
* validated.
*
* If the Sampler is set to SAMPLER_EXTERNAL, external() is implied.
*
* @return
*/
Builder& external() noexcept;
private:
friend class FTexture;
};
@@ -367,7 +359,7 @@ public:
* uint32_t width, uint32_t height, uint32_t depth,
* PixelBufferDescriptor&& buffer)
*/
void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const {
inline 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));
}
@@ -380,7 +372,7 @@ public:
* uint32_t width, uint32_t height, uint32_t depth,
* PixelBufferDescriptor&& buffer)
*/
void setImage(Engine& engine, size_t level,
inline 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));
@@ -414,26 +406,6 @@ 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.
@@ -456,9 +428,7 @@ public:
*
* @see Builder::sampler()
*
* @deprecated Instead, use setExternalImage(Engine& engine, ExternalImageHandleRef image)
*/
UTILS_DEPRECATED
void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept;
/**
@@ -493,7 +463,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
@@ -504,7 +474,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
*
@@ -552,9 +522,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 controlling user-specified quality and options.
* @param options Optional parameter to 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,
-4
View File
@@ -68,10 +68,6 @@ 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;
+5 -11
View File
@@ -116,12 +116,6 @@ static bool fuzzyEqual(mat4f const& UTILS_RESTRICT l, mat4f const& UTILS_RESTRIC
return result == 0;
}
size_t Froxelizer::getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexcept {
// Make sure that targetSize is 16-byte aligned so that it'll fit properly into an array of
// uvec4.
size_t const targetSize = (driverApi.getMaxUniformBufferSize() / 16) * 16;
return std::min(FROXEL_BUFFER_MAX_ENTRY_COUNT * sizeof(FroxelEntry), targetSize);
}
Froxelizer::Froxelizer(FEngine& engine)
: mArena("froxel", PER_FROXELDATA_ARENA_SIZE),
@@ -137,14 +131,14 @@ Froxelizer::Froxelizer(FEngine& engine)
return;
}
size_t const froxelBufferByteCount = getFroxelBufferByteCount(engine.getDriverApi());
mFroxelBufferEntryCount = froxelBufferByteCount / sizeof(FroxelEntry);
mFroxelBufferEntryCount = std::min(
FROXEL_BUFFER_MAX_ENTRY_COUNT,
engine.getDriverApi().getMaxUniformBufferSize() / 16u);
mRecordsBuffer = driverApi.createBufferObject(RECORD_BUFFER_ENTRY_COUNT,
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
mFroxelsBuffer = driverApi.createBufferObject(
froxelBufferByteCount,
mFroxelsBuffer = driverApi.createBufferObject(getFroxelBufferEntryCount() * 16u,
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
}
@@ -533,7 +527,7 @@ std::pair<size_t, size_t> Froxelizer::clipToIndices(float2 const& clip) const no
void Froxelizer::commit(DriverApi& driverApi) {
// send data to GPU
driverApi.updateBufferObject(mFroxelsBuffer,
{ mFroxelBufferUser.data(), getFroxelBufferEntryCount() * sizeof(FroxelEntry) }, 0);
{ mFroxelBufferUser.data(), getFroxelBufferEntryCount() * 16u }, 0);
driverApi.updateBufferObject(mRecordsBuffer,
{ mRecordBufferUser.data(), RECORD_BUFFER_ENTRY_COUNT }, 0);
+7 -11
View File
@@ -35,16 +35,15 @@
namespace filament {
// The number of froxel buffer entries is determined by max UBO size (see
// getFroxelBufferByteCount()). We also introduce the limit below because increasing the number of
// froxels adds more pressure on the "record buffer" which stores the light indices per froxel. The
// record buffer is limited to min(16K[ubo], 64K[uint16]) entries. In practice some froxels are not
// used, so we can store more.
// Max number of froxels limited by:
// - max ubo size [min 16KiB]
//
// Also, increasing the number of froxels adds more pressure on the "record buffer" which stores
// the light indices per froxel. The record buffer is limited to min(16K[ubo], 64K[uint16]) entries,
// so with 8192 froxels, we can store 2 lights per froxels assuming they're all used. In practice,
// some froxels are not used, so we can store more.
constexpr size_t FROXEL_BUFFER_MAX_ENTRY_COUNT = 8192;
// Froxel buffer UBO is an array of uvec4. Make sure that the buffer is properly aligned.
static_assert(FROXEL_BUFFER_MAX_ENTRY_COUNT % 4 == 0u);
class FEngine;
class FCamera;
class FTexture;
@@ -147,7 +146,6 @@ public:
inline uint16_t offset() const noexcept { return u32 >> 16u; }
uint32_t u32 = 0;
};
static_assert(sizeof(FroxelEntry) == 4u);
// we can't change this easily because the shader expects 16 indices per uint4
using RecordBufferType = uint8_t;
@@ -159,8 +157,6 @@ public:
// with 256 lights this implies 8 jobs (256 / 32) for froxelization.
using LightGroupType = uint32_t;
static size_t getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexcept;
private:
size_t getFroxelBufferEntryCount() const noexcept {
return mFroxelBufferEntryCount;
+3 -32
View File
@@ -17,26 +17,6 @@
#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 {
@@ -105,7 +85,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<>
@@ -145,8 +125,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* values, size_t count) {
downcast(this)->setParameterImpl({ name, nameLength }, values, count);
void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* value, size_t count) {
downcast(this)->setParameterImpl({ name, nameLength }, value, count);
}
template<>
@@ -292,11 +272,6 @@ 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);
}
@@ -378,10 +353,6 @@ 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();
}
+4 -11
View File
@@ -807,13 +807,7 @@ 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();
@@ -822,7 +816,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 = cullingMode;
cmd.info.rasterState.culling = mi->getCullingMode();
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
cmd.info.rasterState.depthWrite = (1 // only keep bit 0
@@ -831,12 +825,11 @@ 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,10 +55,6 @@ 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();
}
-12
View File
@@ -58,10 +58,6 @@ 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);
}
@@ -82,10 +78,6 @@ bool Texture::isTextureFormatSupported(Engine& engine, InternalFormat const form
return FTexture::isTextureFormatSupported(downcast(engine), format);
}
bool Texture::isTextureFormatMipmappable(Engine& engine, InternalFormat const format) noexcept {
return FTexture::isTextureFormatMipmappable(downcast(engine), format);
}
bool Texture::isProtectedTexturesSupported(Engine& engine) noexcept {
return FTexture::isProtectedTexturesSupported(downcast(engine));
}
@@ -104,8 +96,4 @@ void Texture::generatePrefilterMipmap(Engine& engine, PixelBufferDescriptor&& bu
downcast(this)->generatePrefilterMipmap(downcast(engine), std::move(buffer), faceOffsets, options);
}
bool Texture::validatePixelFormatAndType(InternalFormat internalFormat, Format format, Type type) noexcept {
return FTexture::validatePixelFormatAndType(internalFormat, format, type);
}
} // namespace filament
+57 -72
View File
@@ -25,9 +25,7 @@
#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"
@@ -38,39 +36,28 @@
#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>
@@ -79,7 +66,6 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "generated/resources/materials.h"
@@ -115,7 +101,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 constexpr (!UTILS_HAS_THREADING) {
if (!UTILS_HAS_THREADING) {
Platform* platform = builder->mPlatform;
void* const sharedContext = builder->mSharedContext;
@@ -137,7 +123,6 @@ Engine* FEngine::create(Builder const& builder) {
.forceGLES2Context = instance->getConfig().forceGLES2Context,
.stereoscopicType = instance->getConfig().stereoscopicType,
.assertNativeWindowIsValid = instance->features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = instance->getConfig().metalDisablePanicOnDrawableFailure,
};
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
@@ -159,7 +144,7 @@ Engine* FEngine::create(Builder const& builder) {
// now we can initialize the largest part of the engine
instance->init();
if constexpr (!UTILS_HAS_THREADING) {
if (!UTILS_HAS_THREADING) {
instance->execute();
}
@@ -178,7 +163,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);
});
@@ -211,7 +196,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] = {
@@ -221,7 +206,7 @@ static constexpr float4 sFullScreenTriangleVertices[3] = {
};
// these must be static because only a pointer is copied to the render stream
static constexpr uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
FEngine::FEngine(Builder const& builder) :
mBackend(builder->mBackend),
@@ -231,6 +216,7 @@ FEngine::FEngine(Builder const& builder) :
mPostProcessManager(*this),
mEntityManager(EntityManager::get()),
mRenderableManager(*this),
mTransformManager(),
mLightManager(*this),
mCameraManager(*this),
mCommandBufferQueue(
@@ -288,7 +274,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;
@@ -361,8 +347,8 @@ void FEngine::init() {
}
// initialize the dummy textures so that their contents are not undefined
static constexpr uint32_t zeroes[6] = {};
static constexpr uint32_t ones = 0xffffffff;
static const uint32_t zeroes[6] = {0};
static const uint32_t ones = 0xffffffff;
mDefaultIblTexture = downcast(Texture::Builder()
.width(1).height(1).levels(1)
@@ -374,7 +360,7 @@ void FEngine::init() {
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
// 3 bands = 9 float3
constexpr float sh[9 * 3] = { 0.0f };
const float sh[9 * 3] = { 0.0f };
mDefaultIbl = downcast(IndirectLight::Builder()
.irradiance(3, reinterpret_cast<const float3*>(sh))
.build(*this));
@@ -441,10 +427,10 @@ void FEngine::init() {
#endif
break;
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
constexpr float3 dummyPositions[1] = {};
constexpr short4 dummyTangents[1] = {};
float3 dummyPositions[1] = {};
short4 dummyTangents[1] = {};
mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0);
mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0);
@@ -467,7 +453,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) {
@@ -483,7 +469,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) {
@@ -621,7 +607,7 @@ void FEngine::shutdown() {
// now wait for all pending commands to be executed and the thread to exit
mCommandBufferQueue.requestExit();
if constexpr (!UTILS_HAS_THREADING) {
if (!UTILS_HAS_THREADING) {
execute();
getDriverApi().terminate();
} else {
@@ -652,13 +638,13 @@ void FEngine::prepare() {
DriverApi& driver = getDriverApi();
for (auto& materialInstanceList: mMaterialInstances) {
materialInstanceList.second.forEach([&driver](FMaterialInstance const* item) {
materialInstanceList.second.forEach([&driver](FMaterialInstance* item) {
item->commit(driver);
});
}
mMaterials.forEach([](FMaterial* material) {
#if FILAMENT_ENABLE_MATDBG // NOLINT(*-include-cleaner)
#if FILAMENT_ENABLE_MATDBG
material->checkProgramEdits();
#endif
});
@@ -682,7 +668,7 @@ void FEngine::flushAndWait() {
flushAndWait(FENCE_WAIT_FOR_EVER);
}
bool FEngine::flushAndWait(uint64_t const timeout) {
bool FEngine::flushAndWait(uint64_t timeout) {
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
<< "Cannot call Engine::flushAndWait() when rendering thread is paused!";
@@ -731,7 +717,6 @@ int FEngine::loop() {
.forceGLES2Context = mConfig.forceGLES2Context,
.stereoscopicType = mConfig.stereoscopicType,
.assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = mConfig.metalDisablePanicOnDrawableFailure,
};
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
@@ -764,7 +749,7 @@ int FEngine::loop() {
}
#endif
#if FILAMENT_ENABLE_FGVIEWER // NOLINT(*-include-cleaner)
#if FILAMENT_ENABLE_FGVIEWER
#ifdef __ANDROID__
const char* fgviewerPortString = "8085";
#else
@@ -794,9 +779,9 @@ int FEngine::loop() {
return 0;
}
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
void FEngine::flushCommandBuffer(CommandBufferQueue& commandQueue) {
getDriver().purge();
commandBufferQueue.flush();
commandQueue.flush();
}
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
@@ -817,7 +802,7 @@ const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
*/
template<typename T, typename ... ARGS>
T* FEngine::create(ResourceList<T>& list,
inline 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)) {
@@ -895,7 +880,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 const pos = mMaterialInstances.emplace(material, "MaterialInstance");
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
pos.first->second.insert(p);
}
return p;
@@ -973,7 +958,7 @@ FCamera* FEngine::createCamera(Entity const entity) noexcept {
}
FCamera* FEngine::getCameraComponent(Entity const entity) noexcept {
auto const ci = mCameraManager.getInstance(entity);
auto ci = mCameraManager.getInstance(entity);
return ci ? mCameraManager.getCamera(ci) : nullptr;
}
@@ -1026,16 +1011,16 @@ void FEngine::cleanupResourceListLocked(Lock& lock, ResourceList<T>&& list) {
template<typename T>
UTILS_ALWAYS_INLINE
bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
inline 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
bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
if (p == nullptr) return true;
bool const success = list.remove(p);
inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
if (ptr == nullptr) return true;
bool const success = list.remove(ptr);
#if UTILS_HAS_RTTI
auto typeName = CallStack::typeName<T>();
@@ -1045,19 +1030,19 @@ bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
#endif
if (ASSERT_PRECONDITION_NON_FATAL(success,
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
const_cast<T*>(p)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(p));
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
const_cast<T*>(ptr)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(ptr));
}
return success;
}
template<typename T, typename Lock>
UTILS_ALWAYS_INLINE
bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>& list) {
if (p == nullptr) return true;
inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, ResourceList<T>& list) {
if (ptr == nullptr) return true;
lock.lock();
bool const success = list.remove(p);
bool const success = list.remove(ptr);
lock.unlock();
#if UTILS_HAS_RTTI
@@ -1068,9 +1053,9 @@ bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>&
#endif
if (ASSERT_PRECONDITION_NON_FATAL(success,
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
const_cast<T*>(p)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(p));
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
const_cast<T*>(ptr)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(ptr));
}
return success;
}
@@ -1163,11 +1148,11 @@ bool FEngine::destroy(const FInstanceBuffer* p){
}
UTILS_NOINLINE
bool FEngine::destroy(const FMaterial* p) {
if (p == nullptr) return true;
bool const success = terminateAndDestroy(p, mMaterials);
bool FEngine::destroy(const FMaterial* ptr) {
if (ptr == nullptr) return true;
bool const success = terminateAndDestroy(ptr, mMaterials);
if (UTILS_LIKELY(success)) {
auto const pos = mMaterialInstances.find(p);
auto pos = mMaterialInstances.find(ptr);
if (UTILS_LIKELY(pos != mMaterialInstances.cend())) {
mMaterialInstances.erase(pos);
}
@@ -1176,8 +1161,8 @@ bool FEngine::destroy(const FMaterial* p) {
}
UTILS_NOINLINE
bool FEngine::destroy(const FMaterialInstance* p) {
if (p == nullptr) return true;
bool FEngine::destroy(const FMaterialInstance* ptr) {
if (ptr == 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
@@ -1193,13 +1178,13 @@ bool FEngine::destroy(const FMaterialInstance* p) {
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 != p)
FILAMENT_CHECK_PRECONDITION(mi != ptr)
<< "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
<< ri.asValue() << ", index=" << j << ")";
} else {
if (UTILS_UNLIKELY(mi == p)) {
if (UTILS_UNLIKELY(mi == ptr)) {
slog.e << "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
@@ -1211,11 +1196,11 @@ bool FEngine::destroy(const FMaterialInstance* p) {
}
}
if (p->isDefaultInstance()) return false;
auto const pos = mMaterialInstances.find(p->getMaterial());
if (ptr->isDefaultInstance()) return false;
auto pos = mMaterialInstances.find(ptr->getMaterial());
assert_invariant(pos != mMaterialInstances.cend());
if (pos != mMaterialInstances.cend()) {
return terminateAndDestroy(p, pos->second);
return terminateAndDestroy(ptr, pos->second);
}
// this shouldn't happen, this would be double-free
return false;
@@ -1268,7 +1253,7 @@ bool FEngine::isValid(const FMaterial* m, const FMaterialInstance* p) const {
}
// then find the material instance list for that material
auto const it = mMaterialInstances.find(m);
auto it = mMaterialInstances.find(m);
if (it == mMaterialInstances.end()) {
// this could happen if this material has no material instances at all
return false;
@@ -1357,7 +1342,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 const buffers = mCommandBufferQueue.waitForCommands();
auto buffers = mCommandBufferQueue.waitForCommands();
if (UTILS_UNLIKELY(buffers.empty())) {
return false;
}
@@ -1396,7 +1381,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));
@@ -1415,7 +1400,7 @@ void FEngine::unprotected() noexcept {
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
}
bool FEngine::setFeatureFlag(char const* name, bool const value) const noexcept {
bool FEngine::setFeatureFlag(char const* name, bool const value) noexcept {
auto* const p = getFeatureFlagPtr(name);
if (p) {
*p = value;
@@ -1486,7 +1471,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 const name : list) {
for (auto name : list) {
if (name) {
feature(name, true);
}
@@ -1515,15 +1500,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)); // NOLINT(*-include-cleaner)
(uint32_t)FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB);
config.perFrameCommandsSizeMB = std::max(
config.perFrameCommandsSizeMB,
uint32_t(FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
(uint32_t)FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB);
config.perRenderPassArenaSizeMB = std::max(
config.perRenderPassArenaSizeMB,
uint32_t(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
(uint32_t)FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB);
config.commandBufferSizeMB = std::max(
config.commandBufferSizeMB,
+13 -15
View File
@@ -61,8 +61,6 @@
#include <filament/Texture.h>
#include <filament/VertexBuffer.h>
#include <backend/DriverEnums.h>
#include <utils/Allocator.h>
#include <utils/compiler.h>
#include <utils/CountDownLatch.h>
@@ -124,11 +122,12 @@ class ResourceAllocator;
*/
class FEngine : public Engine {
public:
void* operator new(std::size_t const size) noexcept {
inline void* operator new(std::size_t const size) noexcept {
return utils::aligned_alloc(size, alignof(FEngine));
}
void operator delete(void* p) noexcept {
inline void operator delete(void* p) noexcept {
utils::aligned_free(p);
}
@@ -491,7 +490,7 @@ public:
backend::Handle<backend::HwTexture> getOneTextureArray() const { return mDummyOneTextureArray; }
backend::Handle<backend::HwTexture> getZeroTextureArray() const { return mDummyZeroTextureArray; }
static constexpr size_t MiB = 1024u * 1024u;
static constexpr const 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; }
@@ -511,15 +510,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) const;
void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue);
backend::Driver& getDriver() const noexcept { return *mDriver; }
template<typename T>
bool isValid(const T* ptr, ResourceList<T> const& list) const;
@@ -691,9 +690,11 @@ public:
bool use_shadow_atlas = false;
} shadows;
struct {
// TODO: default the following two flags to true.
#ifndef NDEBUG
bool assert_material_instance_in_use = true;
#else
bool assert_material_instance_in_use = false;
bool assert_destroy_material_before_material_instance = false;
#endif
} debug;
} engine;
struct {
@@ -720,17 +721,14 @@ public:
&features.engine.shadows.use_shadow_atlas, false },
{ "features.engine.debug.assert_material_instance_in_use",
"Assert when a MaterialInstance is destroyed while it is in use by RenderableManager.",
&features.engine.debug.assert_material_instance_in_use, false },
{ "features.engine.debug.assert_destroy_material_before_material_instance",
"Assert when a Material is destroyed but its instances are still alive.",
&features.engine.debug.assert_destroy_material_before_material_instance, false },
&features.engine.debug.assert_material_instance_in_use, false }
}};
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
return { mFeatures.data(), mFeatures.size() };
}
bool setFeatureFlag(char const* name, bool value) const noexcept;
bool setFeatureFlag(char const* name, bool value) noexcept;
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
};
+6 -16
View File
@@ -383,14 +383,9 @@ void FMaterial::terminate(FEngine& engine) {
auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList();
auto pos = materialInstanceResourceList.find(this);
if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) {
if (engine.features.engine.debug.assert_destroy_material_before_material_instance) {
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
} else {
utils::slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
}
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
}
@@ -980,9 +975,9 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
int const maxInstanceCount = (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)
? 1 : CONFIG_MAX_INSTANCES;
// The 16u below denotes the 16 bytes in a uvec4, which is how the froxel buffer is stored.
int const maxFroxelBufferHeight =
int(Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()) / 16u);
int const maxFroxelBufferHeight = int(std::min(
FROXEL_BUFFER_MAX_ENTRY_COUNT / 4,
engine.getDriverApi().getMaxUniformBufferSize() / 16u));
bool const staticTextureWorkaround =
engine.getDriverApi().isWorkaroundNeeded(Workaround::METAL_STATIC_TEXTURE_TARGET_ERROR);
@@ -1103,13 +1098,8 @@ 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 -10
View File
@@ -61,7 +61,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
: mMaterial(material),
mDescriptorSet(material->getDescriptorSetLayout()),
mCulling(CullingMode::BACK),
mShadowCulling(CullingMode::BACK),
mDepthFunc(RasterState::DepthFunc::LE),
mColorWrite(false),
mDepthWrite(false),
@@ -93,7 +92,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
// We inherit the resolved culling mode rather than the builder-set culling mode.
// This preserves the property whereby double-sidedness automatically disables culling.
mCulling = rasterState.culling;
mShadowCulling = rasterState.culling;
mColorWrite = rasterState.colorWrite;
mDepthWrite = rasterState.depthWrite;
mDepthFunc = rasterState.depthFunc;
@@ -128,7 +126,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
mSpecularAntiAliasingVariance(other->mSpecularAntiAliasingVariance),
mSpecularAntiAliasingThreshold(other->mSpecularAntiAliasingThreshold),
mCulling(other->mCulling),
mShadowCulling(other->mShadowCulling),
mDepthFunc(other->mDepthFunc),
mColorWrite(other->mColorWrite),
mDepthWrite(other->mDepthWrite),
@@ -199,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 const& engine = mMaterial->getEngine();
FEngine& engine = mMaterial->getEngine();
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
Handle<HwTexture> handle = p.texture->getHwHandleForSampling();
assert_invariant(handle);
mDescriptorSet.setSampler(binding, handle, p.params);
}
@@ -219,7 +216,7 @@ void FMaterialInstance::commit(DriverApi& driver) const {
void FMaterialInstance::setParameter(std::string_view const name,
Handle<HwTexture> texture, SamplerParams const params) {
auto const binding = mMaterial->getSamplerBinding(name);
auto binding = mMaterial->getSamplerBinding(name);
mDescriptorSet.setSampler(binding, texture, params);
}
@@ -246,7 +243,7 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
}
#endif
auto const binding = mMaterial->getSamplerBinding(name);
auto binding = mMaterial->getSamplerBinding(name);
if (texture && texture->textureHandleCanMutate()) {
mTextureParameters[binding] = { texture, sampler.getSamplerParams() };
} else {
@@ -331,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 const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
return item.binding == binding;
});
// just safety-check, should never fail
@@ -371,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 const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
return item.binding == binding;
});
+3 -15
View File
@@ -94,8 +94,6 @@ 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,15 +135,7 @@ public:
void setTransparencyMode(TransparencyMode mode) noexcept;
void setCullingMode(CullingMode const culling) noexcept {
mCulling = culling;
mShadowCulling = culling;
}
void setCullingMode(CullingMode const color, CullingMode const shadow) noexcept {
mCulling = color;
mShadowCulling = shadow;
}
void setCullingMode(CullingMode const culling) noexcept { mCulling = culling; }
void setColorWrite(bool const enable) noexcept { mColorWrite = enable; }
@@ -281,9 +271,7 @@ 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;
@@ -295,8 +283,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;
+2 -5
View File
@@ -1351,11 +1351,8 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
}
if (hasFXAA) {
bool const preserveAlphaChannel =
// we're transparent -- alpha channel has user data
needsAlphaChannel ||
// the color-grading pass outputted the luminance channel, and we have an upscaling pass
(hasColorGrading && colorGradingConfig.outputLuminance && scaled);
bool const preserveAlphaChannel = needsAlphaChannel ||
(hasColorGrading && colorGradingConfig.outputLuminance);
input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat, preserveAlphaChannel);
// the padded buffer is resolved now
xvp.left = xvp.bottom = 0;
-5
View File
@@ -546,11 +546,6 @@ 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;
-1
View File
@@ -199,7 +199,6 @@ private:
void addEntities(const utils::Entity* entities, size_t count);
void remove(utils::Entity entity);
void removeEntities(const utils::Entity* entities, size_t count);
void removeAllEntities() noexcept;
size_t getEntityCount() const noexcept { return mEntities.size(); }
size_t getRenderableCount() const noexcept;
size_t getLightCount() const noexcept;
-24
View File
@@ -469,26 +469,6 @@ void FTexture::setImage(FEngine& engine, size_t const level,
const_cast<FTexture*>(this)->updateLodRange(level);
}
void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept {
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
// The call to setupExternalImage2 is synchronous, and allows the driver to take ownership of the
// external image on this thread, if necessary.
auto& api = engine.getDriverApi();
api.setupExternalImage2(image);
auto texture = api.createTextureExternalImage2(mTarget, mFormat, mWidth, mHeight, mUsage, image);
if (mTextureIsSwizzled) {
auto const& s = mSwizzle;
auto swizzleView = api.createTextureViewSwizzle(texture, s[0], s[1], s[2], s[3]);
api.destroyTexture(texture);
texture = swizzleView;
}
setHandles(texture);
}
void FTexture::setExternalImage(FEngine& engine, void* image) noexcept {
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
@@ -658,10 +638,6 @@ bool FTexture::isTextureFormatSupported(FEngine& engine, InternalFormat const fo
return engine.getDriverApi().isTextureFormatSupported(format);
}
bool FTexture::isTextureFormatMipmappable(FEngine& engine, InternalFormat const format) noexcept {
return engine.getDriverApi().isTextureFormatMipmappable(format);
}
bool FTexture::isProtectedTexturesSupported(FEngine& engine) noexcept {
return engine.getDriverApi().isProtectedTexturesSupported();
}
-4
View File
@@ -66,7 +66,6 @@ public:
PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets,
PrefilterOptions const* options);
void setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept;
void setExternalImage(FEngine& engine, void* image) noexcept;
void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept;
void setExternalStream(FEngine& engine, FStream* stream) noexcept;
@@ -89,9 +88,6 @@ public:
// Synchronous call to the backend. Returns whether a backend supports a particular format.
static bool isTextureFormatSupported(FEngine& engine, InternalFormat format) noexcept;
// Synchronous call to the backend. Returns whether a backend supports mipmapping of a particular format.
static bool isTextureFormatMipmappable(FEngine& engine, InternalFormat format) noexcept;
// Synchronous call to the backend. Returns whether a backend supports protected textures.
static bool isProtectedTexturesSupported(FEngine& engine) noexcept;
-1
View File
@@ -126,7 +126,6 @@ FView::FView(FEngine& engine)
mDefaultColorGrading = mColorGrading = engine.getDefaultColorGrading();
mColorPassDescriptorSet.init(
engine,
mLightUbh,
mFroxelizer.getRecordBuffer(),
mFroxelizer.getFroxelBuffer());
+3 -3
View File
@@ -126,17 +126,16 @@ ColorPassDescriptorSet::ColorPassDescriptorSet(FEngine& engine,
}
void ColorPassDescriptorSet::init(
FEngine& engine,
BufferObjectHandle lights,
BufferObjectHandle recordBuffer,
BufferObjectHandle froxelBuffer) noexcept {
for (auto&& descriptorSet: mDescriptorSet) {
descriptorSet.setBuffer(+PerViewBindingPoints::LIGHTS,
lights, 0, CONFIG_MAX_LIGHT_COUNT * sizeof(LightsUib));
lights, 0, sizeof(LightsUib));
descriptorSet.setBuffer(+PerViewBindingPoints::RECORD_BUFFER,
recordBuffer, 0, sizeof(FroxelRecordUib));
descriptorSet.setBuffer(+PerViewBindingPoints::FROXEL_BUFFER,
froxelBuffer, 0, Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()));
froxelBuffer, 0, sizeof(FroxelsUib));
}
}
@@ -574,3 +573,4 @@ void ColorPassDescriptorSet::setBuffer(descriptor_binding_t const binding,
}
} // namespace filament
-1
View File
@@ -79,7 +79,6 @@ public:
TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
void init(
FEngine& engine,
backend::BufferObjectHandle lights,
backend::BufferObjectHandle recordBuffer,
backend::BufferObjectHandle froxelBuffer) noexcept;
+8 -30
View File
@@ -32,7 +32,6 @@
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
@@ -489,7 +488,7 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
const auto activePassNodesEnd = mActivePassNodesEnd;
while (first != activePassNodesEnd) {
PassNode *const pass = *first;
++first;
first++;
assert_invariant(!pass->isCulled());
std::vector<fgviewer::ResourceId> reads;
@@ -497,12 +496,7 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
for (auto const &edge: readEdges) {
// all incoming edges should be valid by construction
assert_invariant(mGraph.isEdgeValid(edge));
auto resourceNode = static_cast<const ResourceNode*>(mGraph.getNode(edge->from));
assert_invariant(resourceNode);
if (resourceNode->getRefCount() == 0)
continue;
reads.push_back(resourceNode->resourceHandle.index);
reads.push_back(edge->from);
}
std::vector<fgviewer::ResourceId> writes;
@@ -513,35 +507,19 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
if (!mGraph.isEdgeValid(edge)) {
continue;
}
auto resourceNode = static_cast<const ResourceNode*>(mGraph.getNode(edge->to));
assert_invariant(resourceNode);
if (resourceNode->getRefCount() == 0)
continue;
writes.push_back(resourceNode->resourceHandle.index);
writes.push_back(edge->to);
}
passes.emplace_back(utils::CString(pass->getName()),
std::move(reads), std::move(writes));
}
std::unordered_map<fgviewer::ResourceId, fgviewer::FrameGraphInfo::Resource> resources;
for (const auto &resourceNode: mResourceNodes) {
const FrameGraphHandle resourceHandle = resourceNode->resourceHandle;
if (resources.find(resourceHandle.index) != resources.end())
continue;
for (const auto &resource: mResourceNodes) {
std::vector<fgviewer::FrameGraphInfo::Resource::Property> resourceProps;
if (resourceNode->getRefCount() == 0)
continue;
if (resourceNode->getParentNode() != nullptr) {
resourceProps.emplace_back(fgviewer::FrameGraphInfo::Resource::Property {
.name = "is_subresource",
.value = utils::CString(std::to_string(
resourceNode->getParentHandle().index).data())
});
}
resources.emplace(resourceHandle.index, fgviewer::FrameGraphInfo::Resource(
resourceHandle.index,
utils::CString(resourceNode->getName()),
// TODO: Fill in resource properties
fgviewer::ResourceId id = resource->getId();
resources.emplace(id, fgviewer::FrameGraphInfo::Resource(
id, utils::CString(resource->getName()),
std::move(resourceProps))
);
}
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.57.2"
spec.version = "1.56.7"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.57.2/filament-v1.57.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.7/filament-v1.56.7-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
-1
View File
@@ -23,7 +23,6 @@ set(SRCS
src/ApiHandler.h
src/DebugServer.cpp
src/FrameGraphInfo.cpp
src/JsonWriter.cpp
)
# ==================================================================================================
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 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.
@@ -36,25 +36,17 @@ public:
FrameGraphInfo(FrameGraphInfo const &) = delete;
bool operator==(const FrameGraphInfo& rhs) const;
struct Pass {
Pass(utils::CString name, std::vector<ResourceId> reads,
std::vector<ResourceId> writes);
bool operator==(const Pass& rhs) const;
utils::CString name;
std::vector<ResourceId> reads;
std::vector<ResourceId> writes;
};
struct Resource {
bool operator==(const Resource& rhs) const;
struct Property {
bool operator==(const Property& rhs) const;
utils::CString name;
utils::CString value;
};
@@ -78,12 +70,6 @@ public:
// The incoming passes should be sorted by the execution order.
void setPasses(std::vector<Pass> sortedPasses);
const char* getViewName() const;
const std::vector<Pass>& getPasses() const;
const std::unordered_map<ResourceId, Resource>& getResources() const;
private:
utils::CString viewName;
// The order of the passes in the vector indicates the execution
+19 -87
View File
@@ -18,7 +18,6 @@
#include "ApiHandler.h"
#include <fgviewer/DebugServer.h>
#include <fgviewer/JsonWriter.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Log.h>
@@ -41,96 +40,29 @@ auto const error = [](int line, std::string const& uri) {
} // anonymous
bool ApiHandler::handleGetApiFgInfo(struct mg_connection* conn,
struct mg_request_info const* request) {
auto const softError = [conn, request](char const* msg) {
utils::slog.e << "[fgviewer] DebugServer: " << msg << ": " << request->query_string << utils::io::endl;
mg_printf(conn, kErrorHeader.data(), "application/txt");
mg_write(conn, msg, strlen(msg));
return true;
};
// TODO: Implement the method
return true;
}
void ApiHandler::addFrameGraph(FrameGraphInfo const* framegraph) {
// TODO: Implement the method
}
bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
struct mg_request_info const* request = mg_get_request_info(conn);
std::string const& uri = request->local_uri;
if (uri.find("/api/status") == 0) {
return handleGetStatus(conn, request);
}
if (uri == "/api/framegraphs") {
std::unique_lock const lock(mServer->mViewsMutex);
mg_printf(conn, kSuccessHeader.data(), "application/json");
mg_printf(conn, "[");
int index = 0;
for (auto const& view: mServer->mViews) {
bool const last = (++index) == mServer->mViews.size();
JsonWriter writer;
if (!writer.writeFrameGraphInfo(view.second)) {
return error(__LINE__, uri);
}
mg_printf(conn, "{ \"fgid\": \"%8.8x\", %s } %s", view.first, writer.getJsonString(),
last ? "" : ",");
}
mg_printf(conn, "]");
return true;
}
if (uri == "/api/framegraph") {
const FrameGraphInfo* result = getFrameGraphInfo(request);
if (!result) {
return error(__LINE__, uri);
}
JsonWriter writer;
if (!writer.writeFrameGraphInfo(*result)) {
return error(__LINE__, uri);
}
mg_printf(conn, kSuccessHeader.data(), "application/json");
mg_printf(conn, "{ %s }", writer.getJsonString());
return true;
}
return error(__LINE__, uri);
}
void ApiHandler::updateFrameGraph(ViewHandle view_handle) {
std::unique_lock const lock(mStatusMutex);
snprintf(statusFrameGraphId, sizeof(statusFrameGraphId), "%8.8x", view_handle);
mCurrentStatus++;
mStatusCondition.notify_all();
}
const FrameGraphInfo* ApiHandler::getFrameGraphInfo(struct mg_request_info const* request) {
size_t const qlength = strlen(request->query_string);
char fgid[9] = {};
if (mg_get_var(request->query_string, qlength, "fgid", fgid, sizeof(fgid)) < 0) {
return nullptr;
}
uint32_t const id = strtoul(fgid, nullptr, 16);
std::unique_lock const lock(mServer->mViewsMutex);
const auto it = mServer->mViews.find(id);
return it == mServer->mViews.end()
? nullptr
: &(it->second);
}
bool ApiHandler::handleGetStatus(struct mg_connection* conn,
struct mg_request_info const* request) {
char const* qstr = request->query_string;
if (qstr && strcmp(qstr, "firstTime") == 0) {
mg_printf(conn, kSuccessHeader.data(), "application/txt");
mg_write(conn, "0", 1);
return true;
}
std::unique_lock<std::mutex> lock(mStatusMutex);
uint64_t const currentStatusCount = mCurrentStatus;
if (mStatusCondition.wait_for(lock, 10s,
[this, currentStatusCount] {
return currentStatusCount < mCurrentStatus;
})) {
mg_printf(conn, kSuccessHeader.data(), "application/txt");
mg_write(conn, statusFrameGraphId, 8);
} else {
mg_printf(conn, kSuccessHeader.data(), "application/txt");
// Use '1' to indicate a no-op. This ensures that we don't block forever if the client is
// gone.
mg_write(conn, "1", 1);
}
// TODO: Implement the method
return true;
}
+3 -19
View File
@@ -17,8 +17,6 @@
#ifndef FGVIEWER_APIHANDLER_H
#define FGVIEWER_APIHANDLER_H
#include <fgviewer/DebugServer.h>
#include <CivetServer.h>
namespace filament::fgviewer {
@@ -29,8 +27,7 @@ struct FrameGraphInfo;
// Handles the following REST requests, where {id} is an 8-digit hex string.
//
// GET /api/framegraphs
// GET /api/framegraph?fg={fgid}
// GET /api/status
// GET /api/framegraph?fg={viewname}
//
class ApiHandler : public CivetHandler {
public:
@@ -39,25 +36,12 @@ public:
~ApiHandler() = default;
bool handleGet(CivetServer* server, struct mg_connection* conn);
void updateFrameGraph(ViewHandle view_handle);
void addFrameGraph(FrameGraphInfo const* frameGraph);
private:
const FrameGraphInfo* getFrameGraphInfo(struct mg_request_info const* request);
bool handleGetStatus(struct mg_connection* conn,
struct mg_request_info const* request);
bool handleGetApiFgInfo(struct mg_connection* conn, struct mg_request_info const* request);
DebugServer* mServer;
std::mutex mStatusMutex;
std::condition_variable mStatusCondition;
char statusFrameGraphId[9] = {};
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
// will always block until statusMaterialId is updated again. The client is expected to keep
// calling /api/status (a constant "pull" to simulate a push).
uint64_t mCurrentStatus = 0;
};
} // filament::fgviewer
-12
View File
@@ -110,7 +110,6 @@ ViewHandle DebugServer::createView(utils::CString name) {
std::unique_lock<utils::Mutex> lock(mViewsMutex);
ViewHandle handle = mViewCounter++;
mViews.emplace(handle, FrameGraphInfo(std::move(name)));
mApiHandler->updateFrameGraph(handle);
return handle;
}
@@ -122,19 +121,8 @@ void DebugServer::destroyView(ViewHandle h) {
void DebugServer::update(ViewHandle h, FrameGraphInfo info) {
std::unique_lock<utils::Mutex> lock(mViewsMutex);
const auto it = mViews.find(h);
if (it == mViews.end()) {
slog.w << "[fgviewer] Received update for unknown handle " << h;
return;
}
bool has_changed = !(it->second == info);
if (!has_changed)
return;
mViews.erase(h);
mViews.emplace(h, std::move(info));
mApiHandler->updateFrameGraph(h);
}
} // namespace filament::fgviewer
+1 -32
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 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.
@@ -25,33 +25,15 @@ FrameGraphInfo::~FrameGraphInfo() = default;
FrameGraphInfo::FrameGraphInfo(FrameGraphInfo&& rhs) noexcept = default;
bool FrameGraphInfo::operator==(const FrameGraphInfo& rhs) const {
return viewName == rhs.viewName
&& passes == rhs.passes
&& resources == rhs.resources;
}
FrameGraphInfo::Pass::Pass(utils::CString name, std::vector<ResourceId> reads,
std::vector<ResourceId> writes): name(std::move(name)),
reads(std::move(reads)),
writes(std::move(writes)) {}
bool FrameGraphInfo::Pass::operator==(const Pass& rhs) const {
return name == rhs.name && reads == rhs.reads && writes == rhs.writes;
}
FrameGraphInfo::Resource::Resource(ResourceId id, utils::CString name,
std::vector<Property> properties): id(id),
name(std::move(name)), properties(std::move(properties)) {}
bool FrameGraphInfo::Resource::operator==(const Resource& rhs) const {
return id == rhs.id && name == rhs.name && properties == rhs.properties;
}
bool FrameGraphInfo::Resource::Property::operator==(const Property &rhs) const {
return name == rhs.name && value == rhs.value;
}
void FrameGraphInfo::setResources(
std::unordered_map<ResourceId, Resource> resources) {
this->resources = std::move(resources);
@@ -61,17 +43,4 @@ void FrameGraphInfo::setPasses(std::vector<Pass> sortedPasses) {
passes = std::move(sortedPasses);
}
const char* FrameGraphInfo::getViewName() const {
return viewName.c_str_safe();
}
const std::vector<FrameGraphInfo::Pass>& FrameGraphInfo::getPasses() const {
return passes;
}
const std::unordered_map<ResourceId, FrameGraphInfo::Resource>&
FrameGraphInfo::getResources() const {
return resources;
}
} // namespace filament::fgviewer
-135
View File
@@ -1,135 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fgviewer/JsonWriter.h>
#include <fgviewer/FrameGraphInfo.h>
#include <iomanip>
#include <sstream>
namespace filament::fgviewer {
namespace {
void writeJSONString(std::ostream& os, const char* str) {
os << '"';
const char* p = str;
while (*p != '\0') {
switch (*p) {
case '"': os << "\\\""; break;
case '\\': os << "\\\\"; break;
case '\n': os << "\\n"; break;
case '\t': os << "\\t"; break;
default: os << *p; break;
}
++p;
}
os << '"';
}
void writeViewName(std::ostream& os, const FrameGraphInfo& frameGraph) {
os << " \"viewName\": ";
writeJSONString(os, frameGraph.getViewName());
os << ",\n";
}
void writeResourceIds(std::ostream& os, const std::vector<ResourceId>& resources) {
for (size_t j = 0; j < resources.size(); ++j) {
os << resources[j];
if (j + 1 < resources.size()) os << ", ";
}
}
void writePasses(std::ostream& os, const FrameGraphInfo& frameGraph) {
os << " \"passes\": [\n";
auto& passes = frameGraph.getPasses();
for (size_t i = 0; i < passes.size(); ++i) {
const FrameGraphInfo::Pass& pass = passes[i];
os << " {\n";
os << " \"name\": ";
writeJSONString(os, pass.name.c_str());
os << ",\n";
const std::vector<ResourceId>& reads = pass.reads;
os << " \"reads\": [";
writeResourceIds(os, reads);
os << "],\n";
const std::vector<ResourceId>& writes = pass.writes;
os << " \"writes\": [";
writeResourceIds(os, writes);
os << "]\n";
os << " }";
if (i + 1 < passes.size()) os << ",";
os << "\n";
}
os << " ],\n";
}
void writeResources(std::ostream& os, const FrameGraphInfo& frameGraph) {
os << " \"resources\": {\n";
size_t resourceCount = 0;
auto& resources = frameGraph.getResources();
for (const auto& [id, resource] : resources) {
os << " \"" << id << "\": {\n";
os << " \"id\": " << resource.id << ",\n";
os << " \"name\": ";
writeJSONString(os, resource.name.c_str());
os << ",\n";
os << " \"properties\": [\n";
for (size_t j = 0; j < resource.properties.size(); ++j) {
const auto& [key, value] = resource.properties[j];
os << " {\n";
os << " \"key\": ";
writeJSONString(os, key.c_str());
os << ",\n";
os << " \"value\": ";
writeJSONString(os, value.c_str());
os << "\n }";
if (j + 1 < resource.properties.size()) os << ",";
os << "\n";
}
os << " ]\n";
os << " }";
if (++resourceCount < resources.size()) os << ",";
os << "\n";
}
os << " }\n";
}
} // anonymous
const char* JsonWriter::getJsonString() const {
return mJsonString.c_str();
}
size_t JsonWriter::getJsonSize() const {
return mJsonString.size();
}
bool JsonWriter::writeFrameGraphInfo(const FrameGraphInfo& frameGraph) {
std::ostringstream os;
writeViewName(os, frameGraph);
writePasses(os, frameGraph);
writeResources(os, frameGraph);
mJsonString = utils::CString(os.str().c_str());
return true;
}
} // namespace filament::fgviewer
-67
View File
@@ -1,67 +0,0 @@
/*
* 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.
*/
// api.js encapsulates all the REST endpoints that the server provides
async function _fetchJson(uri) {
const response = await fetch(uri);
return await response.json();
}
async function _fetchText(uri) {
const response = await fetch(uri);
return await response.text();
}
async function fetchFrameGraphs() {
const fgJson = await _fetchJson("api/framegraphs")
const ret = {};
for (const fgInfo of fgJson) {
ret[fgInfo.fgid] = fgInfo;
}
return ret;
}
async function fetchFrameGraph(fgid) {
const fgInfo = await _fetchJson(`api/framegraph?fgid=${fgid}`);
fgInfo.fgid = fgid;
return fgInfo;
}
const STATUS_LOOP_TIMEOUT = 3000;
const STATUS_CONNECTED = 1;
const STATUS_DISCONNECTED = 2;
const STATUS_FRAMEGRAPH_UPDATED = 3;
// Status function should be of the form function(status, data)
async function statusLoop(isConnected, onStatus) {
// This is a hanging get except for when transition from disconnected to connected, which
// should return immediately.
try {
const fgid = await _fetchText("api/status" + (isConnected() ? '' : '?firstTime'));
// A first-time request returned successfully
if (fgid === '0') {
onStatus(STATUS_CONNECTED);
} else if (fgid !== '1') {
onStatus(STATUS_FRAMEGRAPH_UPDATED, fgid);
} // fgid == '1' is no-op, just loop again
statusLoop(isConnected, onStatus);
} catch {
onStatus(STATUS_DISCONNECTED);
setTimeout(() => statusLoop(isConnected, onStatus), STATUS_LOOP_TIMEOUT)
}
}
-529
View File
@@ -1,529 +0,0 @@
/*
* 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.
*/
import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module";
const kUntitledPlaceholder = "untitled";
// CSS constants
const FOREGROUND_COLOR = '#fafafa';
const INACTIVE_COLOR = '#6f6f6f';
const UNSELECTED_COLOR = '#dfdfdf';
const BACKGROUND_COLOR = '#5362e5';
const REGULAR_FONT_SIZE = 12;
// Constants for color operations
const READ_COLOR = '#3ac224';
const WRITE_COLOR = '#d43232';
const NO_ACCESS_COLOR = '#d8dde754';
const READ_WRITE_COLOR = '#ffeb99';
const DEFAULT_COLOR = '#ffffff';
const SUBRESOURCE_COLOR = '#d3d3d3';
const RESOURCE_USAGE_TYPE_READ = 'read';
const RESOURCE_USAGE_TYPE_WRITE = 'write';
const RESOURCE_USAGE_TYPE_NO_ACCESS = 'no-access';
const RESOURCE_USAGE_TYPE_READ_WRITE = 'read-write';
const IS_SUBRESOURCE_KEY = 'is_subresource'
class MenuSection extends LitElement {
static get properties() {
return {
showing: {type: Boolean, state: true},
title: {type: String, attribute: 'title'},
};
}
static get styles() {
return css`
:host {
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
color: ${unsafeCSS(UNSELECTED_COLOR)};
}
.section-title {
font-size: 16px;
color: ${unsafeCSS(UNSELECTED_COLOR)};
cursor: pointer;
}
.container {
margin-bottom: 20px;
}
hr {
display: block;
height: 1px;
border: 0px;
border-top: 1px solid ${unsafeCSS(UNSELECTED_COLOR)};
padding: 0;
width: 100%;
margin: 3px 0 8px 0;
}
.expander {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
`;
}
_showClick() {
this.showing = !this.showing;
}
constructor() {
super();
this.showing = true;
}
render() {
const expandedIcon = this.showing ? '-' : '+';
const slot = (() => html`
<slot></slot>`)();
return html`
<div class="container">
<div class="section-title expander" @click="${this._showClick}">
<span>${this.title}</span> <span>${expandedIcon}</span>
</div>
<hr/>
${this.showing ? slot : []}
</div>
`;
}
}
customElements.define('menu-section', MenuSection);
class FrameGraphSidePanel extends LitElement {
// Setting the style in render() has poor performance implications. We use it simply to avoid
// having another container descending from the root to host the background color.
dynamicStyle() {
return `
:host {
position: fixed;
background: ${this.connected ? BACKGROUND_COLOR : INACTIVE_COLOR};
width: 20%;
height: 100%;
max-width: 250px;
min-width: 250px;
padding: 10px 20px;
overflow-y: auto;
}
.title {
color: white;
width: 100%;
text-align: center;
margin: 0 0 10px 0;
font-size: 20px;
}
.framegraphs {
display: flex;
flex-direction: column;
margin-bottom: 20px;
font-size: ${REGULAR_FONT_SIZE}px;
color: ${UNSELECTED_COLOR};
}
.framegraph:hover {
text-decoration: underline;
}
.framegraph {
cursor: pointer;
}
.selected {
font-weight: bolder;
color: ${FOREGROUND_COLOR};
}
`;
}
static get properties() {
return {
connected: {type: Boolean, attribute: 'connected'},
currentFrameGraph: {type: String, attribute: 'current-framegraph'},
database: {type: Object, state: true},
framegraphs: {type: Array, state: true},
}
}
constructor() {
super();
this.connected = false;
this.framegraphs = [];
this.database = {};
}
updated(props) {
if (props.has('database')) {
const items = [];
// Names need not be unique, so we display a numeric suffix for non-unique names.
// To achieve stable ordering of anonymous framegraphs, we first sort by fgid.
const labels = new Set();
const fgids = Object.keys(this.database).sort();
const duplicatedLabels = {};
for (const fgid of fgids) {
const name = this.database[fgid].viewName || kUntitledPlaceholder;
if (labels.has(name)) {
duplicatedLabels[name] = 0;
} else {
labels.add(name);
}
}
this.framegraphs = fgids.map((fgid) => {
const framegraph = this.database[fgid];
let name = framegraph.viewName || kUntitledPlaceholder;
if (name in duplicatedLabels) {
const index = duplicatedLabels[name];
duplicatedLabels[name] = index + 1;
name = `${name} (${index})`;
}
return {
fgid: fgid,
name: name,
domain: "views"
};
});
}
}
_handleFrameGraphClick(ev) {
this.dispatchEvent(new CustomEvent('select-framegraph', {
detail: ev,
bubbles: true,
composed: true
}));
}
render() {
const sections = (title) => {
const fgs = this.framegraphs
.map((fg) => {
const framegraph = this.database[fg.fgid];
const onClick = this._handleFrameGraphClick.bind(this, fg.fgid);
const isFrameGraphSelected = fg.fgid === this.currentFrameGraph;
const fgName = (isFrameGraphSelected ? '● ' : '') + framegraph.viewName;
return html`
<div class="framegraph" @click="${onClick}" data-id="${fg.fgid}">
${fgName}
</div>
`;
});
if (fgs.length > 0) {
return html`
<menu-section title="${title}">${fgs}</menu-section>`;
}
return null;
};
return html`
<style>${this.dynamicStyle()}</style>
<div class="container">
<div class="title">fgviewer</div>
${sections("Views", "views") ?? nothing}
</div>
`;
}
}
customElements.define("framegraph-sidepanel", FrameGraphSidePanel);
class FrameGraphTable extends LitElement {
static get styles() {
return css`
:host {
display: block;
flex-grow: 1;
width: 80%;
}
.table-container {
max-height: 100%;
max-width: 100%;
overflow: auto;
border: 1px solid #ddd;
margin-left: 300px;
}
.scrollable-table {
width: 100%;
height: 100%;
border-collapse: collapse;
}
.collapsible {
background-color: #f9f9f9;
}
.toggle-icon {
cursor: pointer;
margin-right: 5px;
user-select: none;
}
.hidden {
display: none;
}
.scrollable-table td,
.scrollable-table th {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
.scrollable-table tr {
position: sticky;
padding: 12px;
text-align: left;
border: 1px solid #ddd;
left: 0;
z-index: 1;
}
.sticky-col {
position: sticky;
left: 0;
z-index: 1;
}
th {
min-width: 100px;
background-color: #f2f2f2;
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
`;
}
static get properties() {
return {
frameGraphData: {type: Object, state: true}, // Expecting a JSON frame graph structure
};
}
constructor() {
super();
this.frameGraphData = null;
}
updated(props) {
if (props.has('frameGraphData')) {
this.requestUpdate();
}
}
_getCellColor(type, defaultColor) {
switch (type) {
case RESOURCE_USAGE_TYPE_READ:
return READ_COLOR;
case RESOURCE_USAGE_TYPE_WRITE:
return WRITE_COLOR;
case RESOURCE_USAGE_TYPE_NO_ACCESS:
return NO_ACCESS_COLOR;
case RESOURCE_USAGE_TYPE_READ_WRITE:
return READ_WRITE_COLOR;
default:
return defaultColor;
}
}
_toggleCollapse(resourceIndex) {
const subresourceRows = this.shadowRoot.querySelectorAll(`[id^="subresource-${resourceIndex}-"]`);
const icon = this.shadowRoot.querySelector(`#resource-${resourceIndex} .toggle-icon`);
const isHidden = subresourceRows[0]?.classList.contains('hidden');
subresourceRows.forEach(row => row.classList.toggle('hidden'));
icon.textContent = isHidden ? '▼' : '▶';
}
_getRowHtml(allPasses, resourceId, defaultColor) {
return allPasses.map((passData, index) => {
const isRead = passData?.reads.includes(resourceId);
const isWrite = passData?.writes.includes(resourceId);
let type = null;
const hasUsed = (passData) => {
return passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId);
};
const hasBeenUsedBefore = allPasses.slice(0, index).some(hasUsed);
const willBeUsedLater = allPasses.slice(index + 1).some(hasUsed);
if (isRead && isWrite) type = RESOURCE_USAGE_TYPE_READ_WRITE;
else if (isRead) type = RESOURCE_USAGE_TYPE_READ;
else if (isWrite) type = RESOURCE_USAGE_TYPE_WRITE;
else if (hasBeenUsedBefore && willBeUsedLater) type = RESOURCE_USAGE_TYPE_NO_ACCESS;
return html`
<td style="background-color: ${unsafeCSS(this._getCellColor(type, defaultColor))};">
${type ?? nothing}
</td>`;
});
}
_isSubresourceOfParent(resource, parentResource){
return resource.properties?.some(prop =>
prop.key === IS_SUBRESOURCE_KEY &&
Number(prop.value) === parentResource.id)
}
render() {
if (!this.frameGraphData || !this.frameGraphData.passes || !this.frameGraphData.resources) return nothing;
const allPasses = this.frameGraphData.passes;
const resources = Object.values(this.frameGraphData.resources);
return html`
<div class="table-container">
<table class="scrollable-table">
<thead>
<tr>
<th class="sticky-col">Resources/Passes</th>
${allPasses.map(pass => html`
<th>${pass.name}</th>`)}
</tr>
</thead>
<tbody>
${resources.map((resource, resourceIndex) => {
const isSubresource = resource.properties?.some(prop => prop.key === IS_SUBRESOURCE_KEY);
if (isSubresource) return nothing;
const hasSubresources = resources.some(subresource => this._isSubresourceOfParent(subresource, resource));
return html`
<tr id="resource-${resourceIndex}">
<th class="sticky-col">
${hasSubresources ? html`
<span
class="toggle-icon"
@click="${() => this._toggleCollapse(resourceIndex)}"
>▶</span>` : nothing}
${resource.name}
</th>
${this._getRowHtml(allPasses, resource.id, DEFAULT_COLOR)}
</tr>
${resources.filter(subresource => this._isSubresourceOfParent(subresource, resource)
).map((subresource, subIndex) => html`
<tr id="subresource-${resourceIndex}-${subIndex}"
class="collapsible hidden">
<td class="sticky-col"
style="background-color: ${SUBRESOURCE_COLOR}">
${subresource.name}
</td>
${this._getRowHtml(allPasses, subresource.id, SUBRESOURCE_COLOR)}
</tr>
`)}
`;
})}
</tbody>
</table>
</div>
`;
}
}
customElements.define("framegraph-table", FrameGraphTable);
class FrameGraphViewer extends LitElement {
static get styles() {
return css`
:host {
height: 100%;
width: 100%;
display: flex;
}
`;
}
get _sidePanel() {
return this.renderRoot.querySelector('#sidepanel');
}
get _framegraphTable() {
return this.renderRoot.querySelector('#table');
}
async init() {
const isConnected = () => this.connected;
statusLoop(
isConnected,
async (status, fgid) => {
this.connected = status == STATUS_CONNECTED || status == STATUS_FRAMEGRAPH_UPDATED;
if (status == STATUS_FRAMEGRAPH_UPDATED) {
let fgInfo = await fetchFrameGraph(fgid);
this.database[fgInfo.fgid] = fgInfo;
this._framegraphTable.frameGraphData = fgInfo;
}
}
);
let framegraphs = await fetchFrameGraphs();
this.database = framegraphs;
}
_getFrameGraph() {
const framegraph = (this.database && this.currentFrameGraph) ?
this.database[this.currentFrameGraph] : null;
return framegraph;
}
constructor() {
super();
this.connected = false;
this.database = {};
this.currentFrameGraph = null;
this.init();
this.addEventListener('select-framegraph',
(ev) => {
this.currentFrameGraph = ev.detail;
}
);
}
static get properties() {
return {
connected: {type: Boolean, state: true},
database: {type: Object, state: true},
currentFrameGraph: {type: String, state: true},
}
}
updated(props) {
if (props.has('currentFrameGraph') || props.has('database')) {
const framegraph = this._getFrameGraph();
this._framegraphTable.frameGraphData = framegraph;
this._sidePanel.database = this.database;
}
}
render() {
return html`
<framegraph-sidepanel id="sidepanel"
?connected="${this.connected}"
current-framegraph="${this.currentFrameGraph}" >
</framegraph-sidepanel>
<framegraph-table id="table"
?connected="${this.connected}"
current-framegraph="${this.currentFrameGraph}"
</framegraph-table>
`;
}
}
customElements.define("framegraph-viewer", FrameGraphViewer);
-22
View File
@@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Filament Debugger</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
<link href="https://google.github.io/filament/favicon.png" rel="icon" type="image/x-icon" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet">
<style>
html, body {
height: 100%;
margin: 0;
font-family: "Open Sans";
}
</style>
<script src="api.js"></script>
</head>
<body>
<script src="app.js" type="module"></script>
<framegraph-viewer></framegraph-viewer>
</body>
</html>
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 57;
static constexpr size_t MATERIAL_VERSION = 56;
/**
* Supported shading models
+15 -13
View File
@@ -144,17 +144,19 @@ install(DIRECTORY ${PUBLIC_HDR_DIR}/filamat DESTINATION include)
# ==================================================================================================
# Tests
# ==================================================================================================
if (IS_HOST_PLATFORM)
project(test_filamat)
set(TARGET test_filamat)
set(SRCS
tests/test_filamat.cpp
tests/test_argBufferFixup.cpp
tests/test_clipDistanceFixup.cpp
tests/test_includes.cpp)
project(test_filamat)
set(TARGET test_filamat)
set(SRCS
tests/test_filamat.cpp
tests/test_argBufferFixup.cpp
tests/test_clipDistanceFixup.cpp
tests/test_includes.cpp)
add_executable(${TARGET} ${SRCS})
target_include_directories(${TARGET} PRIVATE src)
target_link_libraries(${TARGET} filamat gtest)
set_target_properties(${TARGET} PROPERTIES FOLDER Tests)
add_executable(${TARGET} ${SRCS})
target_include_directories(${TARGET} PRIVATE src)
target_link_libraries(${TARGET} filamat gtest)
set_target_properties(${TARGET} PROPERTIES FOLDER Tests)
endif()
+18 -28
View File
@@ -34,54 +34,44 @@
using namespace utils;
namespace {
constexpr uint8_t FAKE_DRY_RUNNER_START_ADDR = 0x1;
} // anonymous
namespace filamat {
class Flattener {
public:
explicit Flattener(uint8_t* dst) : mCursor(dst), mStart(dst){}
// DryRunner is used to compute the size of the flattened output but not actually carry out
// flattening. If we set mStart = nullptr and mEnd=nullptr, we would hit an error about
// offsetting on null when ubsan is enabled. Instead we point mStart to a fake address, and
// mCursor is offset from that.
static Flattener& getDryRunner() {
static Flattener dryRunner = Flattener(nullptr);
dryRunner.mStart = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
dryRunner.mCursor = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
dryRunner.mStart = nullptr;
dryRunner.mCursor = nullptr;
dryRunner.mOffsetPlaceholders.clear();
dryRunner.mSizePlaceholders.clear();
dryRunner.mValuePlaceholders.clear();
return dryRunner;
}
bool isDryRunner() {
return mStart == (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
}
bool isDryRunner() { return mStart == nullptr;}
size_t getBytesWritten() {
return mCursor - mStart;
}
void writeBool(bool b) {
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = static_cast<uint8_t>(b);
}
mCursor += 1;
}
void writeUint8(uint8_t i) {
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = i;
}
mCursor += 1;
}
void writeUint16(uint16_t i) {
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
}
@@ -89,7 +79,7 @@ public:
}
void writeUint32(uint32_t i) {
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
mCursor[2] = static_cast<uint8_t>((i >> 16) & 0xff);
@@ -99,7 +89,7 @@ public:
}
void writeUint64(uint64_t i) {
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
mCursor[2] = static_cast<uint8_t>((i >> 16) & 0xff);
@@ -114,7 +104,7 @@ public:
void writeString(const char* str) {
size_t const len = strlen(str);
if (!isDryRunner()) {
if (mStart != nullptr) {
strcpy(reinterpret_cast<char*>(mCursor), str);
}
mCursor += len + 1;
@@ -122,7 +112,7 @@ public:
void writeString(std::string_view str) {
size_t const len = str.length();
if (!isDryRunner()) {
if (mStart != nullptr) {
memcpy(reinterpret_cast<char*>(mCursor), str.data(), len);
mCursor[len] = 0;
}
@@ -131,14 +121,14 @@ public:
void writeBlob(const char* blob, size_t nbytes) {
writeUint64(nbytes);
if (!isDryRunner()) {
if (mStart != nullptr) {
memcpy(reinterpret_cast<char*>(mCursor), blob, nbytes);
}
mCursor += nbytes;
}
void writeRaw(const char* raw, size_t nbytes) {
if (!isDryRunner()) {
if (mStart != nullptr) {
memcpy(reinterpret_cast<char*>(mCursor), raw, nbytes);
}
mCursor += nbytes;
@@ -146,7 +136,7 @@ public:
void writeSizePlaceholder() {
mSizePlaceholders.push_back(mCursor);
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = 0;
mCursor[1] = 0;
mCursor[2] = 0;
@@ -174,7 +164,7 @@ public:
mSizePlaceholders.pop_back();
// -4 to account for the 4 bytes we are about to write.
uint32_t const size = static_cast<uint32_t>(mCursor - dst - 4);
if (!isDryRunner()) {
if (mStart != nullptr) {
dst[0] = static_cast<uint8_t>( size & 0xff);
dst[1] = static_cast<uint8_t>((size >> 8) & 0xff);
dst[2] = static_cast<uint8_t>((size >> 16) & 0xff);
@@ -185,7 +175,7 @@ public:
void writeOffsetplaceholder(size_t index) {
mOffsetPlaceholders.insert(std::pair<size_t, uint8_t*>(index, mCursor));
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = 0x0;
mCursor[1] = 0x0;
mCursor[2] = 0x0;
@@ -195,7 +185,7 @@ public:
}
void writeOffsets(uint32_t forIndex) {
if (isDryRunner()) {
if (mStart == nullptr) {
return;
}
@@ -219,7 +209,7 @@ public:
void writeValuePlaceholder() {
mValuePlaceholders.push_back(mCursor);
if (!isDryRunner()) {
if (mStart != nullptr) {
mCursor[0] = 0;
mCursor[1] = 0;
mCursor[2] = 0;
@@ -238,7 +228,7 @@ public:
uint8_t* dst = mValuePlaceholders.back();
mValuePlaceholders.pop_back();
if (!isDryRunner()) {
if (mStart != nullptr) {
dst[0] = static_cast<uint8_t>( v & 0xff);
dst[1] = static_cast<uint8_t>((v >> 8) & 0xff);
dst[2] = static_cast<uint8_t>((v >> 16) & 0xff);
+33 -6
View File
@@ -295,12 +295,35 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL",
+ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL, 1);
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
if (mTargetApi == TargetApi::VULKAN) {
// Note: This is a hack for a hack.
//
// Vulkan doesn't support sizing arrays within a block with specialization constants,
// as per this paragraph of the ARB_spir_v specification:
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt
//
// Arrays inside a block may be sized with a specialization constant,
// but the block will have a static layout. Changing the specialized size will
// not re-layout the block. In the absence of explicit offsets, the layout will be
// based on the default size of the array.
//
// CONFIG_MAX_INSTANCES is only needed for WebGL, so we can replace it with a constant.
// CONFIG_FROXEL_BUFFER_HEIGHT can be hardcoded to 2048 because only 3% of Android devices
// only support 16KiB buffer or less (1024 lines).
//
// We *could* leave these as a specialization constant, but this triggers a crashing bug with
// some Adreno drivers on Android. see: https://github.com/google/filament/issues/6444
//
out << "const int CONFIG_MAX_INSTANCES = " << (int)CONFIG_MAX_INSTANCES << ";\n";
out << "const int CONFIG_FROXEL_BUFFER_HEIGHT = 2048;\n";
} else {
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
// the default of 1024 (16KiB) is needed for 32% of Android devices
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
// the default of 1024 (16KiB) is needed for 32% of Android devices
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
}
// directional shadowmap visualization
generateSpecializationConstant(out, "CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP",
@@ -342,6 +365,8 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
out << '\n';
out << SHADERS_COMMON_DEFINES_GLSL_DATA;
CodeGenerator::generateDefine(out, "MATERIAL_FEATURE_LEVEL", uint32_t(mFeatureLevel));
if (material.featureLevel == FeatureLevel::FEATURE_LEVEL_0 &&
(mFeatureLevel > FeatureLevel::FEATURE_LEVEL_0
|| mTargetLanguage == TargetLanguage::SPIRV)) {
@@ -462,7 +487,7 @@ io::sstream& CodeGenerator::generateCommonVariable(io::sstream& out, ShaderStage
return out;
}
io::sstream& CodeGenerator::generateSurfaceShaderInputs(io::sstream& out, ShaderStage stage,
io::sstream& CodeGenerator::generateSurfaceInputs(io::sstream& out, ShaderStage stage,
const AttributeBitset& attributes, Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const {
auto const& attributeDatabase = MaterialBuilder::getAttributeDatabase();
@@ -494,6 +519,7 @@ io::sstream& CodeGenerator::generateSurfaceShaderInputs(io::sstream& out, Shader
}
out << "\n";
out << SHADERS_COMMON_VARYINGS_GLSL_DATA;
out << SHADERS_SURFACE_VARYINGS_GLSL_DATA;
return out;
}
@@ -1050,6 +1076,7 @@ io::sstream& CodeGenerator::generateSurfaceMaterial(io::sstream& out, ShaderStag
}
io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderStage stage) {
out << SHADERS_COMMON_VARYINGS_GLSL_DATA;
if (stage == ShaderStage::VERTEX) {
out << SHADERS_POST_PROCESS_INPUTS_VS_DATA;
} else if (stage == ShaderStage::FRAGMENT) {
+1 -1
View File
@@ -109,7 +109,7 @@ public:
const MaterialBuilder::CustomVariable& variable, size_t index);
// generate declarations for non-custom "in" variables
utils::io::sstream& generateSurfaceShaderInputs(utils::io::sstream& out, ShaderStage stage,
utils::io::sstream& generateSurfaceInputs(utils::io::sstream& out, ShaderStage stage,
const filament::AttributeBitset& attributes, filament::Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const;
static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage stage);
+2 -3
View File
@@ -81,7 +81,6 @@ void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream&
}
out << '\n';
CodeGenerator::generateDefine(out, "MATERIAL_FEATURE_LEVEL", uint32_t(featureLevel));
CodeGenerator::generateDefine(out, "MATERIAL_HAS_SHADOW_MULTIPLIER",
material.hasShadowMultiplier);
@@ -436,7 +435,7 @@ std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel shaderModel,
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::VERTEX;
});
cg.generateSurfaceShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation,
cg.generateSurfaceInputs(vs, ShaderStage::VERTEX, attributes, interpolation,
vertexPushConstants);
CodeGenerator::generateSurfaceTypes(vs, ShaderStage::VERTEX);
@@ -546,7 +545,7 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::FRAGMENT;
});
cg.generateSurfaceShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
cg.generateSurfaceInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
fragmentPushConstants);
CodeGenerator::generateSurfaceTypes(fs, ShaderStage::FRAGMENT);
+9 -2
View File
@@ -704,12 +704,19 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
::prepareNativeWindow(mWindow);
void* metalLayer = nullptr;
if (config.backend == filament::Engine::Backend::METAL || config.backend == filament::Engine::Backend::VULKAN) {
if (config.backend == filament::Engine::Backend::METAL) {
metalLayer = setUpMetalLayer(nativeWindow);
// The swap chain on both native Metal and MoltenVK is a CAMetalLayer.
// The swap chain on Metal is a CAMetalLayer.
nativeSwapChain = metalLayer;
}
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
if (config.backend == filament::Engine::Backend::VULKAN) {
// We request a Metal layer for rendering via MoltenVK.
setUpMetalLayer(nativeWindow);
}
#endif
#endif
// Write back the active feature level.
+2 -11
View File
@@ -988,7 +988,6 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, const char* na
vbb.enableBufferObjects();
bool hasUv0 = false, hasUv1 = false, hasVertexColor = false, hasNormals = false;
int8_t currentCustomIndex = -1;
uint32_t vertexCount = 0;
const size_t firstSlot = slots->size();
@@ -999,7 +998,6 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, const char* na
const int index = attribute.index;
const cgltf_attribute_type atype = attribute.type;
const cgltf_accessor* accessor = attribute.data;
int8_t customIndex = -1;
// The glTF tangent data is ignored here, but honored in ResourceLoader.
if (atype == cgltf_attribute_type_tangent) {
@@ -1017,19 +1015,12 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, const char* na
}
if (atype == cgltf_attribute_type_color) {
if (hasVertexColor) {
// We already had a vertex color before, we need to store this is as a custom
// attribute.
customIndex = ++currentCustomIndex;
} else {
hasVertexColor = true;
}
hasVertexColor = true;
}
// Translate the cgltf attribute enum into a Filament enum.
VertexAttribute semantic;
if (!getCustomVertexAttrType(customIndex, &semantic) &&
!getVertexAttrType(atype, &semantic)) {
if (!getVertexAttrType(atype, &semantic)) {
utils::slog.e << "Unrecognized vertex semantic in " << name << utils::io::endl;
return false;
}
-9
View File
@@ -98,15 +98,6 @@ inline bool getVertexAttrType(cgltf_attribute_type atype, filament::VertexAttrib
}
}
inline bool getCustomVertexAttrType(int8_t customIndex, filament::VertexAttribute* attrType) {
if (customIndex < 0) {
return false;
}
*attrType = static_cast<filament::VertexAttribute>(
customIndex + (uint8_t) filament::VertexAttribute::CUSTOM0);
return true;
}
inline bool getIndexType(cgltf_component_type ctype, filament::IndexBuffer::IndexType* itype) {
switch (ctype) {
case cgltf_component_type_r_8u:
+3
View File
@@ -449,6 +449,9 @@ bool ResourceLoader::loadResources(FFilamentAsset* asset, bool async) {
// that we need to generate the contents of a GPU buffer by processing one or more CPU
// buffer(s).
pImpl->computeTangents(asset);
std::get<FFilamentAsset::ResourceInfo>(asset->mResourceInfo).mBufferSlots.clear();
std::get<FFilamentAsset::ResourceInfo>(asset->mResourceInfo).mPrimitives.clear();
} else {
auto& slots = std::get<FFilamentAsset::ResourceInfoExtended>(asset->mResourceInfo).slots;
ResourceLoaderExtended::loadResources(slots, pImpl->mEngine, asset->mBufferObjects);
+3 -11
View File
@@ -222,13 +222,8 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
}
void ApiHandler::addMaterial(MaterialRecord const* material) {
updateMaterial(material->key);
}
void ApiHandler::updateMaterial(uint32_t key) {
std::unique_lock const lock(mStatusMutex);
mCurrentStatus++;
snprintf(statusMaterialId, sizeof(statusMaterialId), "%8.8x", key);
snprintf(statusMaterialId, sizeof(statusMaterialId), "%8.8x", material->key);
mStatusCondition.notify_all();
}
@@ -293,11 +288,8 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
sstream >> std::hex >> matid >> std::dec >> api >> shaderIndex;
std::string const shader = sstream.str().substr(sstream.tellg());
if (!mServer->handleEditCommand(matid, backend::Backend(api), shaderIndex, shader.c_str(),
shader.size())) {
return error(__LINE__, uri);
}
updateMaterial(matid);
mServer->handleEditCommand(matid, backend::Backend(api), shaderIndex, shader.c_str(),
shader.size());
mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close");
return true;
+1 -3
View File
@@ -55,8 +55,6 @@ private:
bool handleGetStatus(struct mg_connection* conn, struct mg_request_info const* request);
MaterialRecord const* getMaterialRecord(struct mg_request_info const* request);
void updateMaterial(uint32_t key);
DebugServer* mServer;
std::mutex mStatusMutex;
@@ -66,7 +64,7 @@ private:
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
// will always block until statusMaterialId is updated again. The client is expected to keep
// calling /api/status (a constant "pull" to simulate a push).
uint64_t mCurrentStatus = 0;
std::atomic<uint64_t> mCurrentStatus = 0;
SourceFormatter mFormatter;
};
+1 -25
View File
@@ -25,7 +25,6 @@
#include <utils/Log.h>
#include <algorithm>
#include <sstream>
#include <GlslangToSpv.h>
@@ -51,30 +50,10 @@ using namespace glslang;
using namespace utils;
using std::ostream;
using std::streampos;
using std::stringstream;
using std::streampos;
using std::vector;
namespace {
// This is to ensure that the edited material package have the same order of shaders as the output
// of the original material. We use the ordering in the front-end to simplify logic.
template<typename RecordType>
void sortRecords(std::vector<RecordType>& records) {
std::sort(records.begin(), records.end(), [](RecordType const& a, RecordType const& b) -> bool {
if (a.shaderModel != b.shaderModel) {
return a.shaderModel < b.shaderModel;
}
if (a.variant.key != b.variant.key) {
return a.variant.key < b.variant.key;
}
return a.stage < b.stage;
});
}
} // anonymous
// Tiny database of shader text that can import / export MaterialTextChunk and DictionaryTextChunk.
class ShaderIndex {
public:
@@ -365,7 +344,6 @@ void ShaderIndex::writeChunks(ostream& stream) {
for (const auto& record : mShaderRecords) {
lines.addText(record.shader);
}
sortRecords(mShaderRecords);
filamat::ChunkContainer cc;
const auto& dchunk = cc.push<DictionaryTextChunk>(std::move(lines), mDictTag);
@@ -428,8 +406,6 @@ void BlobIndex::writeChunks(ostream& stream) {
}
};
sortRecords(mShaderRecords);
// Apply SMOL-V compression and write out the results.
filamat::ChunkContainer cc;
cc.push<MaterialBinaryChunk>(std::move(mShaderRecords), ChunkType::MaterialSpirv);
+1 -1
View File
@@ -34,7 +34,7 @@ std::string SourceFormatter::format(char const* source) {
while (fgets(output, 1024, fp) != NULL) {}
int status = pclose(fp);
if (!fp || WEXITSTATUS(status)) {
if (!fp || !WEXITSTATUS(status)) {
std::call_once(mClangWarningFlag, []() {
utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
<< "Please make sure it's installed." << utils::io::endl;
+8 -2
View File
@@ -205,11 +205,17 @@ void setup_window(Window& w, Engine* engine) {
void* nativeSwapChain = nativeWindow;
#if defined(__APPLE__)
void* metalLayer = nullptr;
if (kBackend == filament::Engine::Backend::METAL || kBackend == filament::Engine::Backend::VULKAN) {
if (kBackend == filament::Engine::Backend::METAL) {
metalLayer = setUpMetalLayer(nativeWindow);
// The swap chain on both native Metal and MoltenVK is a CAMetalLayer.
// The swap chain on Metal is a CAMetalLayer.
nativeSwapChain = metalLayer;
}
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
if (kBackend == filament::Engine::Backend::VULKAN) {
// We request a Metal layer for rendering via MoltenVK.
setUpMetalLayer(nativeWindow);
}
#endif
#endif
w.swapChain = engine->createSwapChain(nativeSwapChain);
+1
View File
@@ -21,6 +21,7 @@ set(SHADERS
src/surface_material.fs
src/common_math.glsl
src/common_shading.fs
src/common_varyings.glsl
src/surface_shadowing.glsl
src/surface_types.glsl
src/surface_depth_main.fs
+8 -25
View File
@@ -1,27 +1,3 @@
//------------------------------------------------------------------------------
// Common Helpers
//------------------------------------------------------------------------------
/**
* Index of the eye being rendered, starting at 0.
* @public-api
*/
int getEyeIndex() {
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
return instance_index % CONFIG_STEREO_EYE_COUNT;
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
# if defined(TARGET_VULKAN_ENVIRONMENT)
return int(gl_ViewIndex);
# else
// gl_ViewID_OVR is of uint type, which needs an explicit conversion.
return int(gl_ViewID_OVR);
# endif // TARGET_VULKAN_ENVIRONMENT
#endif
return 0;
}
//------------------------------------------------------------------------------
// Uniforms access
//------------------------------------------------------------------------------
@@ -48,7 +24,14 @@ highp mat4 getViewFromClipMatrix() {
/** @public-api */
highp mat4 getClipFromWorldMatrix() {
return frameUniforms.clipFromWorldMatrix[getEyeIndex()];
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
int eye = instance_index % CONFIG_STEREO_EYE_COUNT;
return frameUniforms.clipFromWorldMatrix[eye];
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
return frameUniforms.clipFromWorldMatrix[filament_multiview_data.y];
#else
return frameUniforms.clipFromWorldMatrix[0];
#endif
}
/** @public-api */

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