Merge branch 'google:main' into main
This commit is contained in:
+9
-1
@@ -525,11 +525,14 @@ else()
|
||||
option(FILAMENT_BUILD_FILAMAT "Build filamat and JNI buildings" OFF)
|
||||
endif()
|
||||
|
||||
# By default, link in matdbg for Desktop + Debug only since it pulls in filamat and a web server.
|
||||
# By default, link in matdbg/fgviewer for Desktop + Debug only since it pulls in filamat and a web server.
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND IS_HOST_PLATFORM)
|
||||
option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" ON)
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" ON)
|
||||
else()
|
||||
option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" OFF)
|
||||
option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" OFF)
|
||||
endif()
|
||||
|
||||
# Only optimize materials in Release mode (so error message lines match the source code)
|
||||
@@ -778,6 +781,11 @@ if (FILAMENT_BUILD_FILAMAT OR IS_HOST_PLATFORM)
|
||||
if (FILAMENT_ENABLE_MATDBG OR IS_HOST_PLATFORM)
|
||||
add_subdirectory(${LIBRARIES}/matdbg)
|
||||
endif()
|
||||
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# if (FILAMENT_ENABLE_FGVIEWER OR IS_HOST_PLATFORM)
|
||||
# add_subdirectory(${LIBRARIES}/fgviewer)
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.56.4'
|
||||
implementation 'com.google.android.filament:filament-android:1.56.5'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.56.4'
|
||||
pod 'Filament', '~> 1.56.5'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,6 +7,10 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.56.6
|
||||
|
||||
fix crash: the 'target_node' of Animation Channel may be nullpointer.
|
||||
|
||||
## v1.56.5
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
// com.google.android.filament.exclude-vulkan
|
||||
// When set, support for Vulkan will be excluded.
|
||||
//
|
||||
// com.google.android.filament.fgviewer
|
||||
// When set, enables fgviewer
|
||||
//
|
||||
// com.google.android.filament.matdbg
|
||||
// When set, enables matdbg
|
||||
//
|
||||
@@ -61,6 +64,11 @@ buildscript {
|
||||
.gradleProperty("com.google.android.filament.exclude-vulkan")
|
||||
.isPresent()
|
||||
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// def fgviewer = providers
|
||||
// .gradleProperty("com.google.android.filament.fgviewer")
|
||||
// .isPresent()
|
||||
|
||||
def matdbg = providers
|
||||
.gradleProperty("com.google.android.filament.matdbg")
|
||||
.isPresent()
|
||||
@@ -115,6 +123,8 @@ buildscript {
|
||||
"-DANDROID_STL=c++_static",
|
||||
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// "-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_ENABLE_MATDBG=${matdbg ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_DISABLE_MATOPT=${matnopt ? 'ON' : 'OFF'}".toString()
|
||||
]
|
||||
|
||||
@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.19)
|
||||
project(filament-android)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
|
||||
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
|
||||
|
||||
@@ -51,6 +53,13 @@ add_library(smol-v STATIC IMPORTED)
|
||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# if (FILAMENT_ENABLE_FGVIEWER)
|
||||
# add_library(fgviewer STATIC IMPORTED)
|
||||
# set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||
# ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||
# endif()
|
||||
|
||||
if (FILAMENT_ENABLE_MATDBG)
|
||||
add_library(matdbg STATIC IMPORTED)
|
||||
set_target_properties(matdbg PROPERTIES IMPORTED_LOCATION
|
||||
@@ -117,6 +126,8 @@ target_link_libraries(filament-jni
|
||||
# libgeometry is PUBLIC because gltfio uses it.
|
||||
PUBLIC geometry
|
||||
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# $<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
|
||||
|
||||
@@ -138,6 +138,13 @@ Java_com_google_android_filament_Texture_nBuilderImportTexture(JNIEnv*, jclass,
|
||||
builder->import((intptr_t)id);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderExternal(JNIEnv*, jclass, jlong nativeBuilder) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->external();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
|
||||
@@ -800,6 +800,19 @@ public class Texture {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder external() {
|
||||
nBuilderExternal(mNativeBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>Texture</code> instance.
|
||||
* @param engine The {@link Engine} to associate this <code>Texture</code> with.
|
||||
@@ -1261,6 +1274,7 @@ public class Texture {
|
||||
private static native void nBuilderUsage(long nativeBuilder, int flags);
|
||||
private static native void nBuilderSwizzle(long nativeBuilder, int r, int g, int b, int a);
|
||||
private static native void nBuilderImportTexture(long nativeBuilder, long id);
|
||||
private static native void nBuilderExternal(long nativeBuilder);
|
||||
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
|
||||
|
||||
private static native int nGetWidth(long nativeTexture, int level);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.56.4
|
||||
VERSION_NAME=1.56.5
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ function print_help {
|
||||
echo " This is sometimes needed instead of -c (which still misses some clean steps)."
|
||||
echo " -d"
|
||||
echo " Enable matdbg."
|
||||
echo " -t"
|
||||
echo " Enable fgviewer."
|
||||
echo " -f"
|
||||
echo " Always invoke CMake before incremental builds."
|
||||
echo " -g"
|
||||
@@ -125,6 +127,27 @@ function print_matdbg_help {
|
||||
echo ""
|
||||
}
|
||||
|
||||
function print_fgviewer_help {
|
||||
echo "fgviewer is enabled in the build, but some extra steps are needed."
|
||||
echo ""
|
||||
echo "FOR DESKTOP BUILDS:"
|
||||
echo ""
|
||||
echo "Please set the port environment variable before launching. e.g., on macOS do:"
|
||||
echo " export FILAMENT_FGVIEWER_PORT=8085"
|
||||
echo ""
|
||||
echo "FOR ANDROID BUILDS:"
|
||||
echo ""
|
||||
echo "1) For Android Studio builds, make sure to set:"
|
||||
echo " -Pcom.google.android.filament.fgviewer"
|
||||
echo " option in Preferences > Build > Compiler > Command line options."
|
||||
echo ""
|
||||
echo "2) The port number is hardcoded to 8085 so you will need to do:"
|
||||
echo " adb forward tcp:8085 tcp:8085"
|
||||
echo ""
|
||||
echo "3) Be sure to enable INTERNET permission in your app's manifest file."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")}
|
||||
|
||||
@@ -172,6 +195,7 @@ VULKAN_ANDROID_GRADLE_OPTION=""
|
||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
||||
|
||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
||||
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
|
||||
MATDBG_GRADLE_OPTION=""
|
||||
|
||||
MATOPT_OPTION=""
|
||||
@@ -240,6 +264,7 @@ function build_desktop_target {
|
||||
-DCMAKE_BUILD_TYPE="$1" \
|
||||
-DCMAKE_INSTALL_PREFIX="../${lc_target}/filament" \
|
||||
${EGL_ON_LINUX_OPTION} \
|
||||
${FGVIEWER_OPTION} \
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${ASAN_UBSAN_OPTION} \
|
||||
@@ -376,6 +401,7 @@ function build_android_target {
|
||||
-DFILAMENT_NDK_VERSION="${FILAMENT_NDK_VERSION}" \
|
||||
-DCMAKE_INSTALL_PREFIX="../android-${lc_target}/filament" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="../../build/toolchain-${arch}-linux-android.cmake" \
|
||||
${FGVIEWER_OPTION} \
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${VULKAN_ANDROID_OPTION} \
|
||||
@@ -613,6 +639,7 @@ function build_ios_target {
|
||||
-DPLATFORM_NAME="${platform}" \
|
||||
-DIOS=1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \
|
||||
${FGVIEWER_OPTION} \
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${STEREOSCOPIC_OPTION} \
|
||||
@@ -802,7 +829,7 @@ function check_debug_release_build {
|
||||
|
||||
pushd "$(dirname "$0")" > /dev/null
|
||||
|
||||
while getopts ":hacCfgijmp:q:uvslwedk:bx:S:X:" opt; do
|
||||
while getopts ":hacCfgijmp:q:uvslwedtk:bx:S:X:" opt; do
|
||||
case ${opt} in
|
||||
h)
|
||||
print_help
|
||||
@@ -823,6 +850,12 @@ while getopts ":hacCfgijmp:q:uvslwedk:bx:S:X:" opt; do
|
||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_BUILD_FILAMAT=ON"
|
||||
MATDBG_GRADLE_OPTION="-Pcom.google.android.filament.matdbg"
|
||||
;;
|
||||
t)
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# PRINT_FGVIEWER_HELP=true
|
||||
# FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=ON"
|
||||
#FGVIEWER_GRADLE_OPTION="-Pcom.google.android.filament.fgviewer"
|
||||
;;
|
||||
f)
|
||||
ISSUE_CMAKE_ALWAYS=true
|
||||
;;
|
||||
@@ -1027,3 +1060,7 @@ fi
|
||||
if [[ "${PRINT_MATDBG_HELP}" == "true" ]]; then
|
||||
print_matdbg_help
|
||||
fi
|
||||
|
||||
if [[ "${PRINT_FGVIEWER_HELP}" == "true" ]]; then
|
||||
print_fgviewer_help
|
||||
fi
|
||||
|
||||
@@ -561,6 +561,13 @@ target_link_libraries(${TARGET} PUBLIC filaflat)
|
||||
target_link_libraries(${TARGET} PUBLIC filabridge)
|
||||
target_link_libraries(${TARGET} PUBLIC ibl-lite)
|
||||
|
||||
if (FILAMENT_ENABLE_FGVIEWER)
|
||||
target_link_libraries(${TARGET} PUBLIC fgviewer)
|
||||
add_definitions(-DFILAMENT_ENABLE_FGVIEWER=1)
|
||||
else()
|
||||
add_definitions(-DFILAMENT_ENABLE_FGVIEWER=0)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_ENABLE_MATDBG)
|
||||
target_link_libraries(${TARGET} PUBLIC matdbg)
|
||||
add_definitions(-DFILAMENT_ENABLE_MATDBG=1)
|
||||
|
||||
@@ -214,6 +214,7 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle,
|
||||
backend::TextureSwizzle, a)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage,
|
||||
backend::SamplerType, target,
|
||||
backend::TextureFormat, format,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
@@ -399,17 +400,6 @@ DECL_DRIVER_API_N(update3DImage,
|
||||
DECL_DRIVER_API_N(generateMipmaps,
|
||||
backend::TextureHandle, th)
|
||||
|
||||
// Deprecated
|
||||
DECL_DRIVER_API_N(setExternalImage,
|
||||
backend::TextureHandle, th,
|
||||
void*, image)
|
||||
|
||||
// Deprecated
|
||||
DECL_DRIVER_API_N(setExternalImagePlane,
|
||||
backend::TextureHandle, th,
|
||||
void*, image,
|
||||
uint32_t, plane)
|
||||
|
||||
DECL_DRIVER_API_N(setExternalStream,
|
||||
backend::TextureHandle, th,
|
||||
backend::StreamHandle, sh)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "backend/platforms/PlatformEGLAndroid.h"
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
#elif defined(FILAMENT_IOS)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "backend/platforms/PlatformCocoaTouchGL.h"
|
||||
#endif
|
||||
@@ -88,7 +88,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
*backend = Backend::OPENGL;
|
||||
#elif defined(__ANDROID__)
|
||||
*backend = Backend::OPENGL;
|
||||
#elif defined(IOS) || defined(__APPLE__)
|
||||
#elif defined(FILAMENT_IOS) || defined(__APPLE__)
|
||||
*backend = Backend::METAL;
|
||||
#elif defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
*backend = Backend::VULKAN;
|
||||
@@ -119,7 +119,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
return nullptr;
|
||||
#elif defined(__ANDROID__)
|
||||
return new PlatformEGLAndroid();
|
||||
#elif defined(IOS)
|
||||
#elif defined(FILAMENT_IOS)
|
||||
return new PlatformCocoaTouchGL();
|
||||
#elif defined(__APPLE__)
|
||||
return new PlatformCocoaGL();
|
||||
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
// In practice, MetalRingBuffer is used for argument buffers, which are kept in the constant
|
||||
// address space. Constant buffers have specific alignment requirements when specifying an
|
||||
// offset.
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// The iOS simulator has differing alignment requirements.
|
||||
static constexpr auto METAL_CONSTANT_BUFFER_OFFSET_ALIGNMENT = 256;
|
||||
|
||||
@@ -155,6 +155,7 @@ struct MetalContext {
|
||||
|
||||
RenderPassFlags currentRenderPassFlags;
|
||||
MetalRenderTarget* currentRenderTarget = nullptr;
|
||||
bool validPipelineBound = false;
|
||||
|
||||
// State trackers.
|
||||
PipelineStateTracker pipelineState;
|
||||
|
||||
@@ -482,7 +482,9 @@ void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTextu
|
||||
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
|
||||
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th,
|
||||
backend::SamplerType target,
|
||||
backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
|
||||
mContext->textures.insert(construct_handle<MetalTexture>(
|
||||
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image));
|
||||
@@ -907,7 +909,7 @@ void MetalDriver::terminate() {
|
||||
}
|
||||
|
||||
ShaderModel MetalDriver::getShaderModel() const noexcept {
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
return ShaderModel::MOBILE;
|
||||
#else
|
||||
return ShaderModel::DESKTOP;
|
||||
@@ -981,7 +983,7 @@ bool MetalDriver::isTextureFormatMipmappable(TextureFormat format) {
|
||||
case MTLPixelFormatRGBA16Float:
|
||||
return true;
|
||||
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
// Mipmappable only on desktop:
|
||||
case MTLPixelFormatR32Float:
|
||||
case MTLPixelFormatRG32Float:
|
||||
@@ -989,7 +991,7 @@ bool MetalDriver::isTextureFormatMipmappable(TextureFormat format) {
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
// Mipmappable only on iOS:
|
||||
case MTLPixelFormatRGB9E5Float:
|
||||
return true;
|
||||
@@ -1191,10 +1193,6 @@ void MetalDriver::setupExternalImage(void* image) {
|
||||
CVPixelBufferRetain(pixelBuffer);
|
||||
}
|
||||
|
||||
void MetalDriver::setExternalImage(Handle<HwTexture> th, void* image) {}
|
||||
|
||||
void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {}
|
||||
|
||||
void MetalDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
||||
}
|
||||
|
||||
@@ -1366,7 +1364,7 @@ void MetalDriver::startCapture(int) {
|
||||
if (@available(iOS 13, *)) {
|
||||
MTLCaptureDescriptor* descriptor = [MTLCaptureDescriptor new];
|
||||
descriptor.captureObject = mContext->device;
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
descriptor.destination = MTLCaptureDestinationDeveloperTools;
|
||||
#else
|
||||
descriptor.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
@@ -1430,7 +1428,7 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
width:srcTextureSize.width
|
||||
height:srcTextureSize.height
|
||||
mipmapped:NO];
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
#else
|
||||
textureDescriptor.storageMode = MTLStorageModeManaged;
|
||||
@@ -1449,7 +1447,7 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
|
||||
mContext->blitter->blit(getPendingCommandBuffer(mContext), args, "readPixels blit");
|
||||
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
// Managed textures on macOS require explicit synchronization between GPU / CPU.
|
||||
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(mContext) blitCommandEncoder];
|
||||
[blitEncoder synchronizeResource:readPixelsTexture];
|
||||
@@ -1657,6 +1655,7 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
// during the draw call when the program is invalid. The shader compile error has already been
|
||||
// dumped to the console at this point, so it's fine to simply return early.
|
||||
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!functions)) {
|
||||
mContext->validPipelineBound = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1789,6 +1788,8 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
clamp:0.0];
|
||||
mContext->currentPolygonOffset = ps.polygonOffset;
|
||||
}
|
||||
|
||||
mContext->validPipelineBound = true;
|
||||
}
|
||||
|
||||
void MetalDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
@@ -1886,6 +1887,10 @@ void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t inst
|
||||
<< "draw() without a valid command encoder.";
|
||||
DEBUG_LOG("draw2(...)\n");
|
||||
|
||||
if (FILAMENT_ENABLE_MATDBG && UTILS_UNLIKELY(!mContext->validPipelineBound)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind the offset data.
|
||||
if (mContext->dynamicOffsets.isDirty()) {
|
||||
const auto [size, data] = mContext->dynamicOffsets.getOffsets();
|
||||
|
||||
@@ -196,7 +196,7 @@ inline MTLPixelFormat getMetalFormatLinear(MTLPixelFormat format) {
|
||||
case MTLPixelFormatRG8Unorm_sRGB: return MTLPixelFormatRG8Unorm;
|
||||
case MTLPixelFormatRGBA8Unorm_sRGB: return MTLPixelFormatRGBA8Unorm;
|
||||
case MTLPixelFormatBGRA8Unorm_sRGB: return MTLPixelFormatBGRA8Unorm;
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
case MTLPixelFormatBC1_RGBA_sRGB: return MTLPixelFormatBC1_RGBA;
|
||||
case MTLPixelFormatBC2_RGBA_sRGB: return MTLPixelFormatBC2_RGBA;
|
||||
case MTLPixelFormatBC3_RGBA_sRGB: return MTLPixelFormatBC3_RGBA;
|
||||
@@ -268,7 +268,7 @@ constexpr inline bool isMetalFormatStencil(MTLPixelFormat format) {
|
||||
case MTLPixelFormatStencil8:
|
||||
case MTLPixelFormatDepth32Float_Stencil8:
|
||||
case MTLPixelFormatX32_Stencil8:
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
case MTLPixelFormatDepth24Unorm_Stencil8:
|
||||
case MTLPixelFormatX24_Stencil8:
|
||||
#endif
|
||||
|
||||
@@ -157,7 +157,7 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
textureDescriptor.height = headlessHeight;
|
||||
// Specify MTLTextureUsageShaderRead so the headless surface can be blitted from.
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
#else
|
||||
textureDescriptor.storageMode = MTLStorageModeManaged;
|
||||
@@ -520,7 +520,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
|
||||
const BOOL mipmapped = levels > 1;
|
||||
const BOOL multisampled = samples > 1;
|
||||
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
const BOOL textureArray = target == SamplerType::SAMPLER_2D_ARRAY;
|
||||
FILAMENT_CHECK_PRECONDITION(!textureArray || !multisampled)
|
||||
<< "iOS does not support multisampled texture arrays.";
|
||||
@@ -533,7 +533,7 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
return MTLTextureType2DMultisample;
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return MTLTextureType2DMultisampleArray;
|
||||
#endif
|
||||
@@ -856,7 +856,7 @@ void MetalTexture::loadWithBlit(uint32_t level, uint32_t slice, MTLRegion region
|
||||
descriptor.height = region.size.height;
|
||||
descriptor.depth = region.size.depth;
|
||||
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
descriptor.storageMode = MTLStorageModeShared;
|
||||
#else
|
||||
descriptor.storageMode = MTLStorageModeManaged;
|
||||
|
||||
@@ -37,7 +37,7 @@ Driver* MetalPlatform::createDriver(void* /*sharedContext*/, const Platform::Dri
|
||||
id<MTLDevice> MetalPlatform::createDevice() noexcept {
|
||||
id<MTLDevice> result;
|
||||
|
||||
#if !defined(IOS)
|
||||
#if !defined(FILAMENT_IOS)
|
||||
const bool forceIntegrated =
|
||||
NSProcessInfo.processInfo.environment[@"FILAMENT_FORCE_INTEGRATED_GPU"] != nil;
|
||||
if (forceIntegrated) {
|
||||
|
||||
@@ -150,7 +150,7 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
|
||||
MTLCompareFunctionNever : getCompareFunction(params.compareFunc);
|
||||
samplerDescriptor.supportArgumentBuffers = YES;
|
||||
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
// Older Apple devices (and the simulator) don't support setting a comparison function in
|
||||
// MTLSamplerDescriptor.
|
||||
// In practice, this means shadows are not supported when running in the simulator.
|
||||
|
||||
@@ -32,7 +32,7 @@ Dispatcher NoopDriver::getDispatcher() const noexcept {
|
||||
}
|
||||
|
||||
ShaderModel NoopDriver::getShaderModel() const noexcept {
|
||||
#if defined(__ANDROID__) || defined(IOS) || defined(__EMSCRIPTEN__)
|
||||
#if defined(__ANDROID__) || defined(FILAMENT_IOS) || defined(__EMSCRIPTEN__)
|
||||
return ShaderModel::MOBILE;
|
||||
#else
|
||||
return ShaderModel::DESKTOP;
|
||||
@@ -265,12 +265,6 @@ TimerQueryResult NoopDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64
|
||||
return TimerQueryResult::ERROR;
|
||||
}
|
||||
|
||||
void NoopDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
||||
}
|
||||
|
||||
void NoopDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
||||
}
|
||||
|
||||
void NoopDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
||||
}
|
||||
|
||||
|
||||
@@ -173,6 +173,7 @@ void GLDescriptorSet::update(OpenGLContext& gl,
|
||||
|
||||
arg.target = t ? t->gl.target : 0;
|
||||
arg.id = t ? t->gl.id : 0;
|
||||
arg.external = t ? t->gl.external : false;
|
||||
if constexpr (std::is_same_v<T, Sampler> ||
|
||||
std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
|
||||
if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
|
||||
@@ -285,7 +286,7 @@ void GLDescriptorSet::bind(
|
||||
} else if constexpr (std::is_same_v<T, Sampler>) {
|
||||
GLuint const unit = p.getTextureUnit(set, binding);
|
||||
if (arg.target) {
|
||||
gl.bindTexture(unit, arg.target, arg.id);
|
||||
gl.bindTexture(unit, arg.target, arg.id, arg.external);
|
||||
gl.bindSampler(unit, arg.sampler);
|
||||
if (UTILS_UNLIKELY(arg.ref)) {
|
||||
updateTextureView(gl, handleAllocator, unit, arg);
|
||||
@@ -296,7 +297,7 @@ void GLDescriptorSet::bind(
|
||||
} else if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
|
||||
GLuint const unit = p.getTextureUnit(set, binding);
|
||||
if (arg.target) {
|
||||
gl.bindTexture(unit, arg.target, arg.id);
|
||||
gl.bindTexture(unit, arg.target, arg.id, arg.external);
|
||||
gl.bindSampler(unit, arg.sampler);
|
||||
if (UTILS_UNLIKELY(arg.ref)) {
|
||||
updateTextureView(gl, handleAllocator, unit, arg);
|
||||
@@ -314,7 +315,7 @@ void GLDescriptorSet::bind(
|
||||
// in ES2 the sampler parameters need to be set on the texture itself
|
||||
GLuint const unit = p.getTextureUnit(set, binding);
|
||||
if (arg.target) {
|
||||
gl.bindTexture(unit, arg.target, arg.id);
|
||||
gl.bindTexture(unit, arg.target, arg.id, arg.external);
|
||||
SamplerParams const params = arg.params;
|
||||
glTexParameteri(arg.target, GL_TEXTURE_MIN_FILTER,
|
||||
(GLint)GLUtils::getTextureFilter(params.filterMin));
|
||||
|
||||
@@ -111,7 +111,9 @@ private:
|
||||
|
||||
// A sampler descriptor
|
||||
struct Sampler {
|
||||
GLenum target = 0; // 4
|
||||
uint16_t target; // 2 (GLenum)
|
||||
bool external = false; // 1
|
||||
bool reserved = false; // 1
|
||||
GLuint id = 0; // 4
|
||||
GLuint sampler = 0; // 4
|
||||
Handle<GLTextureRef> ref; // 4
|
||||
@@ -126,7 +128,9 @@ private:
|
||||
};
|
||||
|
||||
struct SamplerWithAnisotropyWorkaround {
|
||||
GLenum target = 0; // 4
|
||||
uint16_t target; // 2 (GLenum)
|
||||
bool external = false; // 1
|
||||
bool reserved = false; // 1
|
||||
GLuint id = 0; // 4
|
||||
GLuint sampler = 0; // 4
|
||||
Handle<GLTextureRef> ref; // 4
|
||||
@@ -143,7 +147,9 @@ private:
|
||||
|
||||
// A sampler descriptor for ES2
|
||||
struct SamplerGLES2 {
|
||||
GLenum target = 0; // 4
|
||||
uint16_t target; // 2 (GLenum)
|
||||
bool external = false; // 1
|
||||
bool reserved = false; // 1
|
||||
GLuint id = 0; // 4
|
||||
SamplerParams params{}; // 4
|
||||
float anisotropy = 1.0f; // 4
|
||||
|
||||
@@ -35,7 +35,7 @@ struct GLTextureRef {
|
||||
GLTextureRef() = default;
|
||||
// view reference counter
|
||||
uint16_t count = 1;
|
||||
// current per-view values of the texture (in GL we can only have a single View active at
|
||||
// Current per-view values of the texture (in GL we can only have a single View active at
|
||||
// a time, and this tracks that state). It's used to avoid unnecessarily change state.
|
||||
int8_t baseLevel = 127;
|
||||
int8_t maxLevel = -1;
|
||||
@@ -50,7 +50,7 @@ struct GLTextureRef {
|
||||
struct GLTexture : public HwTexture {
|
||||
using HwTexture::HwTexture;
|
||||
struct GL {
|
||||
GL() noexcept : imported(false), sidecarSamples(1), reserved1(0) {}
|
||||
GL() noexcept : imported(false), external(false), sidecarSamples(1), reserved1(0) {}
|
||||
GLuint id = 0; // texture or renderbuffer id
|
||||
GLenum target = 0;
|
||||
GLenum internalFormat = 0;
|
||||
@@ -62,7 +62,8 @@ struct GLTexture : public HwTexture {
|
||||
int8_t maxLevel = -1;
|
||||
uint8_t reserved0 = 0;
|
||||
bool imported : 1;
|
||||
uint8_t sidecarSamples : 4;
|
||||
bool external : 1;
|
||||
uint8_t sidecarSamples : 3;
|
||||
uint8_t reserved1 : 3;
|
||||
std::array<TextureSwizzle, 4> swizzle{
|
||||
TextureSwizzle::CHANNEL_0,
|
||||
|
||||
@@ -408,7 +408,7 @@ void OpenGLContext::initProcs(Procs* procs,
|
||||
procs->maxShaderCompilerThreadsKHR = +[](GLuint) {};
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
# ifndef IOS // IOS is guaranteed to have ES3.x
|
||||
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
||||
# ifndef __EMSCRIPTEN__
|
||||
if (UTILS_UNLIKELY(major == 2)) {
|
||||
// Runtime OpenGL version is ES 2.x
|
||||
@@ -438,7 +438,7 @@ void OpenGLContext::initProcs(Procs* procs,
|
||||
procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsKHR;
|
||||
}
|
||||
# endif // __EMSCRIPTEN__
|
||||
# endif // IOS
|
||||
# endif // FILAMENT_IOS
|
||||
#else
|
||||
procs->maxShaderCompilerThreadsKHR = glMaxShaderCompilerThreadsARB;
|
||||
#endif
|
||||
@@ -576,14 +576,14 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
}
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
# ifndef IOS // IOS is guaranteed to have ES3.x
|
||||
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
||||
if (UTILS_UNLIKELY(major == 2)) {
|
||||
if (UTILS_UNLIKELY(!exts.OES_vertex_array_object)) {
|
||||
// we activate this workaround path, which does the reset of array buffer
|
||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||
}
|
||||
}
|
||||
# endif // IOS
|
||||
# endif // FILAMENT_IOS
|
||||
#else
|
||||
// feedback loops are allowed on GL desktop as long as writes are disabled
|
||||
bugs->allow_read_only_ancillary_feedback_loop = true;
|
||||
@@ -622,7 +622,7 @@ FeatureLevel OpenGLContext::resolveFeatureLevel(GLint major, GLint minor,
|
||||
}
|
||||
}
|
||||
}
|
||||
# ifndef IOS // IOS is guaranteed to have ES3.x
|
||||
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
||||
else if (UTILS_UNLIKELY(major == 2)) {
|
||||
// Runtime OpenGL version is ES 2.x
|
||||
// note: mandatory extensions (all supported by Mali-400 and Adreno 304)
|
||||
@@ -634,7 +634,7 @@ FeatureLevel OpenGLContext::resolveFeatureLevel(GLint major, GLint minor,
|
||||
// OES_texture_npot
|
||||
featureLevel = FeatureLevel::FEATURE_LEVEL_0;
|
||||
}
|
||||
# endif // IOS
|
||||
# endif // FILAMENT_IOS
|
||||
#else
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
}
|
||||
|
||||
inline bool isES2() const noexcept {
|
||||
#if defined(BACKEND_OPENGL_VERSION_GLES) && !defined(IOS)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GLES) && !defined(FILAMENT_IOS)
|
||||
# ifndef BACKEND_OPENGL_LEVEL_GLES30
|
||||
return true;
|
||||
# else
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
|
||||
void pixelStore(GLenum, GLint) noexcept;
|
||||
inline void activeTexture(GLuint unit) noexcept;
|
||||
inline void bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept;
|
||||
inline void bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept;
|
||||
|
||||
void unbindTexture(GLenum target, GLuint id) noexcept;
|
||||
void unbindTextureUnit(GLuint unit) noexcept;
|
||||
@@ -761,7 +761,9 @@ void OpenGLContext::bindBufferRange(GLenum target, GLuint index, GLuint buffer,
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexcept {
|
||||
void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId, bool external) noexcept {
|
||||
// another texture is bound to the same unit with a different target,
|
||||
// unbind the texture from the current target
|
||||
update_state(state.textures.units[unit].target, target, [&]() {
|
||||
activeTexture(unit);
|
||||
glBindTexture(state.textures.units[unit].target, 0);
|
||||
@@ -769,7 +771,7 @@ void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId) noexce
|
||||
update_state(state.textures.units[unit].id, texId, [&]() {
|
||||
activeTexture(unit);
|
||||
glBindTexture(target, texId);
|
||||
}, target == GL_TEXTURE_EXTERNAL_OES);
|
||||
}, external);
|
||||
}
|
||||
|
||||
void OpenGLContext::useProgram(GLuint program) noexcept {
|
||||
|
||||
@@ -402,7 +402,7 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||
|
||||
void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept {
|
||||
assert_invariant(t != nullptr);
|
||||
mContext.bindTexture(unit, t->gl.target, t->gl.id);
|
||||
mContext.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external);
|
||||
}
|
||||
|
||||
bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
@@ -1052,17 +1052,49 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
|
||||
createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage);
|
||||
setExternalImage(th, image);
|
||||
void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType target,
|
||||
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* 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) {
|
||||
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::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane) {
|
||||
createTextureR(th, SamplerType::SAMPLER_EXTERNAL, 1, format, 1, width, height, 1, usage);
|
||||
setExternalImagePlane(th, image, plane);
|
||||
// not relevant for the OpenGL backend
|
||||
}
|
||||
|
||||
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
||||
@@ -1082,6 +1114,7 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
t->gl.target = GL_TEXTURE_EXTERNAL_OES;
|
||||
t->gl.external = true; // forces bindTexture() call (they're never cached)
|
||||
break;
|
||||
case SamplerType::SAMPLER_2D:
|
||||
t->gl.target = GL_TEXTURE_2D;
|
||||
@@ -1348,13 +1381,13 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
|
||||
// TODO: support multiview for iOS and WebGL
|
||||
#if !defined(__EMSCRIPTEN__) && !defined(IOS)
|
||||
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
|
||||
if (layerCount > 1) {
|
||||
// if layerCount > 1, it means we use the multiview extension.
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, 0, binfo.layer, layerCount);
|
||||
} else
|
||||
#endif // !defined(__EMSCRIPTEN__) && !defined(IOS)
|
||||
#endif // !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
|
||||
{
|
||||
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
|
||||
@@ -2774,25 +2807,6 @@ void OpenGLDriver::setupExternalImage(void* image) {
|
||||
mPlatform.retainExternalImage(image);
|
||||
}
|
||||
|
||||
void OpenGLDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
||||
DEBUG_MARKER()
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
assert_invariant(t);
|
||||
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);
|
||||
|
||||
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;
|
||||
bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
||||
DEBUG_MARKER()
|
||||
}
|
||||
|
||||
void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
||||
auto& gl = mContext;
|
||||
if (gl.ext.OES_EGL_image_external_essl3) {
|
||||
@@ -3512,7 +3526,7 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
|
||||
auto& gl = mContext;
|
||||
gl.bindVertexArray(nullptr);
|
||||
for (int unit = OpenGLContext::DUMMY_TEXTURE_BINDING; unit >= 0; unit--) {
|
||||
gl.bindTexture(unit, GL_TEXTURE_2D, 0);
|
||||
gl.bindTexture(unit, GL_TEXTURE_2D, 0, false);
|
||||
}
|
||||
gl.disable(GL_CULL_FACE);
|
||||
gl.depthFunc(GL_LESS);
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
# define FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
#endif
|
||||
|
||||
#elif defined(IOS)
|
||||
#elif defined(FILAMENT_IOS)
|
||||
|
||||
#define GLES_SILENCE_DEPRECATION
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
#if defined(GL_VERSION_4_5)
|
||||
#elif defined(GL_ES_VERSION_3_1)
|
||||
#elif defined(GL_ES_VERSION_3_0)
|
||||
# if !defined(IOS) && !defined(__EMSCRIPTEN__)
|
||||
# if !defined(FILAMENT_IOS) && !defined(__EMSCRIPTEN__)
|
||||
# error "GLES 3.0 headers only supported on iOS and WebGL2"
|
||||
# endif
|
||||
#elif defined(GL_ES_VERSION_2_0)
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
#if defined(GL_ES_VERSION_2_0) // this basically means all versions of GLES
|
||||
|
||||
#if defined(IOS)
|
||||
#if defined(FILAMENT_IOS)
|
||||
|
||||
// iOS headers only provide prototypes, nothing to do.
|
||||
|
||||
@@ -271,7 +271,7 @@ void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void *d
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES_VERSION_2_0
|
||||
# ifndef IOS
|
||||
# ifndef FILAMENT_IOS
|
||||
# ifndef GL_OES_vertex_array_object
|
||||
# error "Headers with GL_OES_vertex_array_object are mandatory unless on iOS"
|
||||
# endif
|
||||
|
||||
@@ -715,14 +715,16 @@ void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept {
|
||||
|
||||
bool PlatformEGL::setExternalImage(void* externalImage,
|
||||
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
||||
if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) {
|
||||
assert_invariant(texture->target == GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
// OES_EGL_image_external_essl3 must be present if the target is TEXTURE_EXTERNAL_OES
|
||||
// GL_OES_EGL_image must be present if TEXTURE_2D is used
|
||||
|
||||
#if defined(GL_OES_EGL_image) || defined(GL_OES_EGL_image_external_essl3)
|
||||
// the texture is guaranteed to be bound here.
|
||||
#ifdef GL_OES_EGL_image
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
|
||||
glEGLImageTargetTexture2DOES(texture->target,
|
||||
static_cast<GLeglImageOES>(externalImage));
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont
|
||||
}
|
||||
|
||||
ShaderModel VulkanDriver::getShaderModel() const noexcept {
|
||||
#if defined(__ANDROID__) || defined(IOS)
|
||||
#if defined(__ANDROID__) || defined(FILAMENT_IOS)
|
||||
return ShaderModel::MOBILE;
|
||||
#else
|
||||
return ShaderModel::DESKTOP;
|
||||
@@ -543,7 +543,8 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
texture.inc();
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th,
|
||||
backend::SamplerType target, backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
@@ -1189,13 +1190,6 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
|
||||
return TimerQueryResult::AVAILABLE;
|
||||
}
|
||||
|
||||
void VulkanDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
||||
|
||||
}
|
||||
|
||||
void VulkanDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
||||
}
|
||||
|
||||
void VulkanDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef VK_MVK_macos_surface
|
||||
#error VK_MVK_macos_surface is not defined
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
#elif defined(FILAMENT_IOS)
|
||||
// Metal is not available when building for the iOS simulator on Desktop.
|
||||
#define METAL_AVAILABLE __has_include(<QuartzCore/CAMetalLayer.h>)
|
||||
#if METAL_AVAILABLE
|
||||
@@ -56,7 +56,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
ExtensionSet const ret = {
|
||||
#if defined(__APPLE__)
|
||||
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
|
||||
#elif defined(IOS) && defined(METAL_AVAILABLE)
|
||||
#elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE)
|
||||
VK_MVK_IOS_SURFACE_EXTENSION_NAME,
|
||||
#endif
|
||||
};
|
||||
@@ -90,7 +90,7 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin
|
||||
VkResult result = vkCreateMacOSSurfaceMVK((VkInstance) instance, &createInfo, VKALLOC,
|
||||
(VkSurfaceKHR*) &surface);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateMacOSSurfaceMVK error.";
|
||||
#elif defined(IOS) && defined(METAL_AVAILABLE)
|
||||
#elif defined(FILAMENT_IOS) && defined(METAL_AVAILABLE)
|
||||
CAMetalLayer* metalLayer = (CAMetalLayer*) nativeWindow;
|
||||
// Create the VkSurface.
|
||||
FILAMENT_CHECK_POSTCONDITION(vkCreateIOSSurfaceMVK)
|
||||
|
||||
@@ -33,7 +33,7 @@ static constexpr size_t CONFIG_COMMAND_BUFFERS_SIZE = 3 * CONFIG_MIN_COMMAND
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
@@ -177,7 +177,7 @@ void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, si
|
||||
|
||||
// Export a screenshot, if requested.
|
||||
if (c->exportScreenshot) {
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
LinearImage image(c->width, c->height, 4);
|
||||
image = toLinearWithAlpha<uint8_t>(c->width, c->height, c->width * 4,
|
||||
(uint8_t*) buffer);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
#endif
|
||||
@@ -67,7 +67,7 @@ struct ScreenshotParams {
|
||||
uint32_t pixelHashResult;
|
||||
};
|
||||
|
||||
#ifdef IOS
|
||||
#ifdef FILAMENT_IOS
|
||||
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, ScreenshotParams* params) {}
|
||||
#else
|
||||
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, ScreenshotParams* params) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
@@ -112,7 +112,7 @@ static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt) {
|
||||
int w = kTexWidth, h = kTexHeight;
|
||||
const uint32_t* texels = (uint32_t*) buffer;
|
||||
sPixelHashResult = utils::hash::murmur3(texels, size / 4, 0);
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
LinearImage image(w, h, 4);
|
||||
image = toLinearWithAlpha<uint8_t>(w, h, w * 4, (uint8_t*) buffer);
|
||||
std::ofstream pngstrm("feedback.png", std::ios::binary | std::ios::trunc);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
@@ -137,7 +137,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
}
|
||||
|
||||
void exportScreenshot(void* pixelData) const {
|
||||
#ifndef IOS
|
||||
#ifndef FILAMENT_IOS
|
||||
const size_t width = readRect.width, height = readRect.height;
|
||||
LinearImage image(width, height, 4);
|
||||
if (format == PixelDataFormat::RGBA && type == PixelDataType::UBYTE) {
|
||||
|
||||
@@ -227,7 +227,8 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
|
||||
api.setupExternalImage(pixBuffer);
|
||||
backend::Handle<HwTexture> texture =
|
||||
api.createTextureExternalImage(TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer);
|
||||
api.createTextureExternalImage(SamplerType::SAMPLER_EXTERNAL,
|
||||
TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer);
|
||||
|
||||
// We're now free to release the buffer.
|
||||
CVBufferRelease(pixBuffer);
|
||||
|
||||
@@ -261,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;
|
||||
};
|
||||
@@ -395,7 +407,7 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
* Specify the external image to associate with this Texture. Typically the external
|
||||
* 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
|
||||
@@ -420,7 +432,7 @@ public:
|
||||
void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept;
|
||||
|
||||
/**
|
||||
* Specify the external image and plane to associate with this Texture. Typically the external
|
||||
* Specify the external image and plane to associate with this Texture. Typically, the external
|
||||
* image is OS specific, and can be a video or camera frame. When using this method, the
|
||||
* external image must be a planar type (such as a YUV camera frame). The plane parameter
|
||||
* selects which image plane is bound to this texture.
|
||||
|
||||
@@ -611,13 +611,10 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexce
|
||||
FEngine const& engine = mEngine;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
|
||||
bool const isSharedVariant =
|
||||
(mMaterialDomain == MaterialDomain::SURFACE) &&
|
||||
!mIsDefaultMaterial && !mHasCustomDepthShader &&
|
||||
Variant::isValidDepthVariant(variant);
|
||||
bool const isShared = isSharedVariant(variant);
|
||||
|
||||
// Check if the default material has this program cached
|
||||
if (isSharedVariant) {
|
||||
if (isShared) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial) {
|
||||
auto program = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
@@ -636,7 +633,7 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexce
|
||||
// If the default material doesn't already have this program cached, and all caching conditions
|
||||
// are met (Surface Domain and no custom depth shader), cache it now.
|
||||
// New Materials will inherit these program automatically.
|
||||
if (isSharedVariant) {
|
||||
if (isShared) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
// set the tag to the default material name
|
||||
|
||||
@@ -156,6 +156,13 @@ public:
|
||||
std::unique_lock<utils::Mutex> lock(mActiveProgramsLock);
|
||||
mActivePrograms.set(variant.key);
|
||||
lock.unlock();
|
||||
|
||||
if (isSharedVariant(variant)) {
|
||||
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
return pDefaultMaterial->getProgram(variant);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
assert_invariant(mCachedPrograms[variant.key]);
|
||||
return mCachedPrograms[variant.key];
|
||||
@@ -290,6 +297,11 @@ private:
|
||||
|
||||
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
|
||||
|
||||
inline bool isSharedVariant(Variant variant) const {
|
||||
return (mMaterialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
|
||||
!mHasCustomDepthShader && Variant::isValidDepthVariant(variant);
|
||||
}
|
||||
|
||||
// try to order by frequency of use
|
||||
mutable std::array<backend::Handle<backend::HwProgram>, VARIANT_COUNT> mCachedPrograms;
|
||||
DescriptorSetLayout mPerViewDescriptorSetLayout;
|
||||
|
||||
@@ -81,6 +81,7 @@ struct Texture::BuilderDetails {
|
||||
Usage mUsage = Usage::NONE;
|
||||
bool mHasBlitSrc = false;
|
||||
bool mTextureIsSwizzled = false;
|
||||
bool mExternal = false;
|
||||
std::array<Swizzle, 4> mSwizzle = {
|
||||
Swizzle::CHANNEL_0, Swizzle::CHANNEL_1,
|
||||
Swizzle::CHANNEL_2, Swizzle::CHANNEL_3 };
|
||||
@@ -136,6 +137,11 @@ Texture::Builder& Texture::Builder::import(intptr_t id) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::Builder& Texture::Builder::external() noexcept {
|
||||
mImpl->mExternal = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::Builder& Texture::Builder::swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept {
|
||||
mImpl->mTextureIsSwizzled = true;
|
||||
mImpl->mSwizzle = { r, g, b, a };
|
||||
@@ -154,6 +160,11 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
(isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory)
|
||||
<< "Texture is PROTECTED but protected textures are not supported";
|
||||
|
||||
// SAMPLER_EXTERNAL implies imported.
|
||||
if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) {
|
||||
mImpl->mExternal = true;
|
||||
}
|
||||
|
||||
uint8_t maxLevelCount;
|
||||
switch (mImpl->mTarget) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
@@ -174,7 +185,7 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
mImpl->mUsage = TextureUsage::DEFAULT;
|
||||
if (mImpl->mLevels > 1 &&
|
||||
(mImpl->mWidth > 1 || mImpl->mHeight > 1) &&
|
||||
mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) {
|
||||
!mImpl->mExternal) {
|
||||
const bool formatMipmappable =
|
||||
downcast(engine).getDriverApi().isTextureFormatMipmappable(mImpl->mFormat);
|
||||
if (formatMipmappable) {
|
||||
@@ -243,9 +254,10 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) {
|
||||
mSwizzle = builder->mSwizzle;
|
||||
mTextureIsSwizzled = builder->mTextureIsSwizzled;
|
||||
mHasBlitSrc = builder->mHasBlitSrc;
|
||||
mExternal = builder->mExternal;
|
||||
|
||||
bool const isImported = builder->mImportedId != 0;
|
||||
if (mTarget == SamplerType::SAMPLER_EXTERNAL && !isImported) {
|
||||
if (mExternal && !isImported) {
|
||||
// mHandle and mHandleForSampling will be created in setExternalImage()
|
||||
// If this Texture is used for sampling before setExternalImage() is called,
|
||||
// we'll lazily create a 1x1 placeholder texture.
|
||||
@@ -318,8 +330,8 @@ void FTexture::setImage(FEngine& engine, size_t level,
|
||||
<< "level=" << unsigned(level) << " is >= to levelCount=" << unsigned(mLevelCount)
|
||||
<< ".";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL)
|
||||
<< "Texture SamplerType::SAMPLER_EXTERNAL not supported for this operation.";
|
||||
FILAMENT_CHECK_PRECONDITION(!mExternal)
|
||||
<< "External Texture not supported for this operation.";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mSampleCount <= 1) << "Operation not supported with multisample ("
|
||||
<< unsigned(mSampleCount) << ") texture.";
|
||||
@@ -454,15 +466,14 @@ void FTexture::setImage(FEngine& engine, size_t level,
|
||||
}
|
||||
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image) noexcept {
|
||||
if (mTarget != Sampler::SAMPLER_EXTERNAL) {
|
||||
return;
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
|
||||
// The call to setupExternalImage is synchronous, and allows the driver to take ownership of the
|
||||
// external image on this thread, if necessary.
|
||||
auto& api = engine.getDriverApi();
|
||||
api.setupExternalImage(image);
|
||||
|
||||
auto texture = api.createTextureExternalImage(mFormat, mWidth, mHeight, mUsage, image);
|
||||
auto texture = api.createTextureExternalImage(mTarget, mFormat, mWidth, mHeight, mUsage, image);
|
||||
|
||||
if (mTextureIsSwizzled) {
|
||||
auto const& s = mSwizzle;
|
||||
@@ -475,9 +486,8 @@ void FTexture::setExternalImage(FEngine& engine, void* image) noexcept {
|
||||
}
|
||||
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noexcept {
|
||||
if (mTarget != Sampler::SAMPLER_EXTERNAL) {
|
||||
return;
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
|
||||
// The call to setupExternalImage is synchronous, and allows the driver to take ownership of
|
||||
// the external image on this thread, if necessary.
|
||||
auto& api = engine.getDriverApi();
|
||||
@@ -497,9 +507,7 @@ void FTexture::setExternalImage(FEngine& engine, void* image, size_t plane) noex
|
||||
}
|
||||
|
||||
void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept {
|
||||
if (mTarget != Sampler::SAMPLER_EXTERNAL) {
|
||||
return;
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
|
||||
auto& api = engine.getDriverApi();
|
||||
auto texture = api.createTexture(
|
||||
@@ -524,7 +532,7 @@ void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept {
|
||||
}
|
||||
|
||||
void FTexture::generateMipmaps(FEngine& engine) const noexcept {
|
||||
FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_EXTERNAL)
|
||||
FILAMENT_CHECK_PRECONDITION(!mExternal)
|
||||
<< "External Textures are not mipmappable.";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mTarget != SamplerType::SAMPLER_3D)
|
||||
@@ -544,12 +552,11 @@ void FTexture::generateMipmaps(FEngine& engine) const noexcept {
|
||||
}
|
||||
|
||||
bool FTexture::textureHandleCanMutate() const noexcept {
|
||||
return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) ||
|
||||
mTarget == SamplerType::SAMPLER_EXTERNAL;
|
||||
return (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) || mExternal;
|
||||
}
|
||||
|
||||
void FTexture::updateLodRange(uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||
assert_invariant(mTarget != SamplerType::SAMPLER_EXTERNAL);
|
||||
assert_invariant(!mExternal);
|
||||
if (any(mUsage & Usage::SAMPLEABLE) && mLevelCount > 1) {
|
||||
auto& range = mLodRange;
|
||||
uint8_t const last = int8_t(baseLevel + levelCount);
|
||||
@@ -601,7 +608,7 @@ backend::Handle<backend::HwTexture> FTexture::createPlaceholderTexture(
|
||||
}
|
||||
|
||||
backend::Handle<backend::HwTexture> FTexture::getHwHandleForSampling() const noexcept {
|
||||
if (UTILS_UNLIKELY(mTarget == SamplerType::SAMPLER_EXTERNAL && !mHandleForSampling)) {
|
||||
if (UTILS_UNLIKELY(mExternal && !mHandleForSampling)) {
|
||||
return setHandleForSampling(createPlaceholderTexture(*mDriver));
|
||||
}
|
||||
auto const& range = mLodRange;
|
||||
@@ -610,9 +617,10 @@ backend::Handle<backend::HwTexture> FTexture::getHwHandleForSampling() const noe
|
||||
if (UTILS_UNLIKELY(lodRangeChanged)) {
|
||||
activeRange = range;
|
||||
if (range.empty() || hasAllLods(range)) {
|
||||
setHandleForSampling(mHandle);
|
||||
std::ignore = setHandleForSampling(mHandle);
|
||||
} else {
|
||||
setHandleForSampling(mDriver->createTextureView(mHandle, range.first, range.size()));
|
||||
std::ignore = setHandleForSampling(mDriver->createTextureView(
|
||||
mHandle, range.first, range.size()));
|
||||
}
|
||||
}
|
||||
return mHandleForSampling;
|
||||
|
||||
@@ -173,7 +173,8 @@ private:
|
||||
// Indicates whether the user has set the TextureUsage::BLIT_SRC usage. This will be used to
|
||||
// temporarily validate whether this texture can be used for readPixels.
|
||||
bool mHasBlitSrc = false;
|
||||
// there is 5 bytes of padding here
|
||||
bool mExternal = false;
|
||||
// there is 4 bytes of padding here
|
||||
|
||||
FStream* mStream = nullptr; // only needed for streaming textures
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.56.4"
|
||||
spec.version = "1.56.5"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.4/filament-v1.56.4-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.5/filament-v1.56.5-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR 1
|
||||
#elif defined(IOS)
|
||||
#elif defined(FILAMENT_IOS)
|
||||
#define VK_USE_PLATFORM_IOS_MVK 1
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
project(fgviewer C ASM)
|
||||
|
||||
set(TARGET fgviewer)
|
||||
set(PUBLIC_HDR_DIR include)
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
include(${IMPORT_EXECUTABLES})
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Sources and headers
|
||||
# ==================================================================================================
|
||||
|
||||
set(PUBLIC_HDRS
|
||||
include/fgviewer/DebugServer.h
|
||||
include/fgviewer/JsonWriter.h
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
src/ApiHandler.cpp
|
||||
src/ApiHandler.h
|
||||
src/DebugServer.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
# ==================================================================================================
|
||||
|
||||
include_directories(${PUBLIC_HDR_DIR})
|
||||
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET} PUBLIC
|
||||
civetweb
|
||||
utils
|
||||
)
|
||||
|
||||
target_include_directories(${TARGET} PRIVATE ${filamat_SOURCE_DIR}/src)
|
||||
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
|
||||
# ==================================================================================================
|
||||
# Compiler flags
|
||||
# ==================================================================================================
|
||||
|
||||
if (MSVC)
|
||||
else()
|
||||
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
|
||||
# matdbg has dependencies on non-installed libraries. Here we bundle them all together into a single
|
||||
# library that gets copied into the installation folder so users are only required to link against
|
||||
# matdbg.
|
||||
set(FGVIEWER_DEPS
|
||||
fgviewer
|
||||
civetweb
|
||||
)
|
||||
|
||||
set(FGVIEWER_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libfgviewer_combined.a")
|
||||
combine_static_libs(fgviewer "${FGVIEWER_COMBINED_OUTPUT}" "${FGVIEWER_DEPS}")
|
||||
|
||||
set(FGVIEWER_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}fgviewer${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
install(FILES "${FGVIEWER_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${FGVIEWER_LIB_NAME})
|
||||
# We do not need fgviewer headers in the install directory
|
||||
# install(DIRECTORY ${PUBLIC_HDR_DIR}/fgviewer DESTINATION include)
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FGVIEWER_DEBUGSERVER_H
|
||||
#define FGVIEWER_DEBUGSERVER_H
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class CivetServer;
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
using FrameGraphInfoKey = uint32_t;
|
||||
|
||||
struct FrameGraphPassInfo {
|
||||
utils::CString pass_name;
|
||||
// TODO: Add struct detail properties
|
||||
};
|
||||
|
||||
struct FrameGraphInfo {
|
||||
utils::CString view_name;
|
||||
std::vector<FrameGraphPassInfo> passes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Server-side frame graph debugger.
|
||||
*
|
||||
* This class manages an HTTP server. It receives frame graph packages from the Filament C++ engine or
|
||||
* from a standalone tool such as fginfo.
|
||||
*/
|
||||
class DebugServer {
|
||||
public:
|
||||
static std::string_view const kSuccessHeader;
|
||||
static std::string_view const kErrorHeader;
|
||||
|
||||
DebugServer(int port);
|
||||
~DebugServer();
|
||||
|
||||
/**
|
||||
* Notifies the debugger that a new view has been added.
|
||||
*/
|
||||
void addView(const utils::CString& name, FrameGraphInfo info);
|
||||
|
||||
/**
|
||||
* Notifies the debugger that the given view has been deleted.
|
||||
*/
|
||||
void removeView(const utils::CString& name);
|
||||
|
||||
/**
|
||||
* Updates the information for a given view.
|
||||
*/
|
||||
void updateView(const utils::CString& name, FrameGraphInfo info);
|
||||
|
||||
bool isReady() const { return mServer; }
|
||||
|
||||
private:
|
||||
CivetServer* mServer;
|
||||
|
||||
std::unordered_map<FrameGraphInfoKey, FrameGraphInfo> mViews;
|
||||
mutable utils::Mutex mViewsMutex;
|
||||
|
||||
class FileRequestHandler* mFileHandler = nullptr;
|
||||
class ApiHandler* mApiHandler = nullptr;
|
||||
|
||||
friend class FileRequestHandler;
|
||||
friend class ApiHandler;
|
||||
};
|
||||
|
||||
} // namespace filament::fgviewer
|
||||
|
||||
#endif // FGVIEWER_DEBUGSERVER_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FGVIEWER_JSONWRITER_H
|
||||
#define FGVIEWER_JSONWRITER_H
|
||||
|
||||
#include <utils/CString.h>
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
struct FrameGraphInfo;
|
||||
|
||||
// This class generates portions of JSON messages that are sent to the web client.
|
||||
// Note that some portions of these JSON strings are generated by directly in DebugServer,
|
||||
// as well as CommonWriter.
|
||||
class JsonWriter {
|
||||
public:
|
||||
|
||||
// Retrieves the most recently generated string.
|
||||
const char* getJsonString() const;
|
||||
size_t getJsonSize() const;
|
||||
|
||||
// Generates a JSON string describing the given FrameGraphInfo.
|
||||
bool writeFrameGraphInfo(const FrameGraphInfo& frameGraph);
|
||||
|
||||
private:
|
||||
utils::CString mJsonString;
|
||||
};
|
||||
|
||||
} // namespace filament::fgviewer
|
||||
|
||||
#endif // FGVIEWER_JSONWRITER_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ApiHandler.h"
|
||||
|
||||
#include <fgviewer/DebugServer.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <CivetServer.h>
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace {
|
||||
|
||||
auto const& kSuccessHeader = DebugServer::kSuccessHeader;
|
||||
auto const& kErrorHeader = DebugServer::kErrorHeader;
|
||||
|
||||
auto const error = [](int line, std::string const& uri) {
|
||||
utils::slog.e << "[fgviewer] DebugServer: 404 at line " << line << ": " << uri << utils::io::endl;
|
||||
return false;
|
||||
};
|
||||
|
||||
} // 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;
|
||||
|
||||
// TODO: Implement the method
|
||||
return true;
|
||||
}
|
||||
|
||||
} // filament::fgviewer
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FGVIEWER_APIHANDLER_H
|
||||
#define FGVIEWER_APIHANDLER_H
|
||||
|
||||
#include <CivetServer.h>
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
class DebugServer;
|
||||
struct FrameGraphInfo;
|
||||
|
||||
// Handles the following REST requests, where {id} is an 8-digit hex string.
|
||||
//
|
||||
// GET /api/framegraphs
|
||||
// GET /api/framegraph?fg={viewname}
|
||||
//
|
||||
class ApiHandler : public CivetHandler {
|
||||
public:
|
||||
explicit ApiHandler(DebugServer* server)
|
||||
: mServer(server) {}
|
||||
~ApiHandler() = default;
|
||||
|
||||
bool handleGet(CivetServer* server, struct mg_connection* conn);
|
||||
void addFrameGraph(FrameGraphInfo const* frameGraph);
|
||||
|
||||
private:
|
||||
bool handleGetApiFgInfo(struct mg_connection* conn, struct mg_request_info const* request);
|
||||
|
||||
DebugServer* mServer;
|
||||
};
|
||||
|
||||
} // filament::fgviewer
|
||||
|
||||
#endif // FGVIEWER_APIHANDLER_H
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fgviewer/DebugServer.h>
|
||||
|
||||
#include "ApiHandler.h"
|
||||
|
||||
#include <CivetServer.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
namespace {
|
||||
std::string const BASE_URL = "libs/fgviewer/web";
|
||||
|
||||
FrameGraphInfoKey getKeybyString(const utils::CString &input,
|
||||
uint32_t seed) {
|
||||
return utils::hash::murmurSlow(reinterpret_cast<uint8_t const*>(
|
||||
input.c_str()), input.size(), 0);
|
||||
}
|
||||
} // anonymous
|
||||
|
||||
using namespace utils;
|
||||
|
||||
std::string_view const DebugServer::kSuccessHeader =
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n"
|
||||
"Connection: close\r\n\r\n";
|
||||
|
||||
std::string_view const DebugServer::kErrorHeader =
|
||||
"HTTP/1.1 404 Not Found\r\nContent-Type: %s\r\n"
|
||||
"Connection: close\r\n\r\n";
|
||||
|
||||
class FileRequestHandler : public CivetHandler {
|
||||
public:
|
||||
FileRequestHandler(DebugServer* server) : mServer(server) {}
|
||||
bool handleGet(CivetServer *server, struct mg_connection *conn) {
|
||||
auto const& kSuccessHeader = DebugServer::kSuccessHeader;
|
||||
struct mg_request_info const* request = mg_get_request_info(conn);
|
||||
std::string uri(request->request_uri);
|
||||
if (uri == "/") {
|
||||
uri = "/index.html";
|
||||
}
|
||||
|
||||
if (uri == "/index.html" || uri == "/app.js" || uri == "/api.js") {
|
||||
mg_send_file(conn, (BASE_URL + uri).c_str());
|
||||
return true;
|
||||
}
|
||||
slog.e << "[fgviewer] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
DebugServer* mServer;
|
||||
};
|
||||
|
||||
DebugServer::DebugServer(int port) {
|
||||
// By default the server spawns 50 threads so we override this to 10. According to the civetweb
|
||||
// documentation, "it is recommended to use num_threads of at least 5, since browsers often
|
||||
/// establish multiple connections to load a single web page, including all linked documents
|
||||
// (CSS, JavaScript, images, ...)." If this count is too small, the web app basically hangs.
|
||||
const char* kServerOptions[] = {
|
||||
"listening_ports", "8085",
|
||||
"num_threads", "10",
|
||||
"error_log_file", "civetweb.txt",
|
||||
nullptr
|
||||
};
|
||||
std::string portString = std::to_string(port);
|
||||
kServerOptions[1] = portString.c_str();
|
||||
|
||||
mServer = new CivetServer(kServerOptions);
|
||||
if (!mServer->getContext()) {
|
||||
delete mServer;
|
||||
mServer = nullptr;
|
||||
slog.e << "[fgviewer] Unable to start DebugServer, see civetweb.txt for details." << io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
mFileHandler = new FileRequestHandler(this);
|
||||
mApiHandler = new ApiHandler(this);
|
||||
|
||||
mServer->addHandler("/api", mApiHandler);
|
||||
mServer->addHandler("", mFileHandler);
|
||||
|
||||
slog.i << "[fgviewer] DebugServer listening at http://localhost:" << port << io::endl;
|
||||
}
|
||||
|
||||
DebugServer::~DebugServer() {
|
||||
mServer->close();
|
||||
|
||||
delete mFileHandler;
|
||||
delete mApiHandler;
|
||||
delete mServer;
|
||||
}
|
||||
|
||||
void DebugServer::addView(const utils::CString &name, FrameGraphInfo info) {
|
||||
std::unique_lock<utils::Mutex> lock(mViewsMutex);
|
||||
const FrameGraphInfoKey key = getKeybyString(name, 0);
|
||||
mViews.insert({key, info});
|
||||
}
|
||||
|
||||
void DebugServer::removeView(const utils::CString& name) {
|
||||
std::unique_lock<utils::Mutex> lock(mViewsMutex);
|
||||
const FrameGraphInfoKey key = getKeybyString(name, 0);
|
||||
mViews.erase(key);
|
||||
}
|
||||
|
||||
void DebugServer::updateView(const utils::CString& name, FrameGraphInfo info) {
|
||||
std::unique_lock<utils::Mutex> lock(mViewsMutex);
|
||||
const FrameGraphInfoKey key = getKeybyString(name, 0);
|
||||
mViews[key] = info;
|
||||
}
|
||||
|
||||
} // namespace filament::fgviewer
|
||||
@@ -645,7 +645,7 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
|
||||
|
||||
// This mirrors the logic for choosing a backend given compile-time flags and client having
|
||||
// provided DEFAULT as the backend (see PlatformFactory.cpp)
|
||||
#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(IOS) && \
|
||||
#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(FILAMENT_IOS) && \
|
||||
!defined(__APPLE__) && defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
if (backend == Engine::Backend::DEFAULT) {
|
||||
backend = Engine::Backend::VULKAN;
|
||||
|
||||
@@ -408,6 +408,9 @@ void AnimatorImpl::addChannels(const FixedCapacityVector<Entity>& nodeMap,
|
||||
const Sampler* samplers = dst.samplers.data();
|
||||
for (cgltf_size j = 0, nchans = srcAnim.channels_count; j < nchans; ++j) {
|
||||
const cgltf_animation_channel& srcChannel = srcChannels[j];
|
||||
if (!srcChannel.target_node) {
|
||||
continue;
|
||||
}
|
||||
Entity targetEntity = nodeMap[srcChannel.target_node - nodes];
|
||||
if (UTILS_UNLIKELY(!targetEntity)) {
|
||||
if (GLTFIO_VERBOSE) {
|
||||
|
||||
@@ -1733,7 +1733,7 @@ void FAssetLoader::importSkins(FFilamentInstance* instance, const cgltf_data* gl
|
||||
}
|
||||
|
||||
bool AssetConfigurationExtended::isSupported() {
|
||||
#if defined(__ANDROID__) || defined(IOS) || defined(__EMSCRIPTEN__)
|
||||
#if defined(__ANDROID__) || defined(FILAMENT_IOS) || defined(__EMSCRIPTEN__)
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
#define GLTFIO_WARN(msg) slog.w << msg << io::endl
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(IOS)
|
||||
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(FILAMENT_IOS)
|
||||
#define GLTFIO_USE_FILESYSTEM 0
|
||||
#else
|
||||
#define GLTFIO_USE_FILESYSTEM 1
|
||||
|
||||
@@ -31,6 +31,8 @@ set(SRCS
|
||||
src/ShaderReplacer.cpp
|
||||
src/ShaderExtractor.cpp
|
||||
src/ShaderInfo.cpp
|
||||
src/SourceFormatter.cpp
|
||||
src/SourceFormatter.h
|
||||
src/TextWriter.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -43,19 +43,6 @@ namespace {
|
||||
auto const& kSuccessHeader = DebugServer::kSuccessHeader;
|
||||
auto const& kErrorHeader = DebugServer::kErrorHeader;
|
||||
|
||||
void spirvToAsm(struct mg_connection* conn, uint32_t const* spirv, size_t size) {
|
||||
auto spirvDisassembly = ShaderExtractor::spirvToText(spirv, size / 4);
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size());
|
||||
}
|
||||
|
||||
void spirvToGlsl(ShaderModel shaderModel, struct mg_connection* conn, uint32_t const* spirv,
|
||||
size_t size) {
|
||||
auto glsl = ShaderExtractor::spirvToGLSL(shaderModel, spirv, size / 4);
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_printf(conn, glsl.c_str(), glsl.size());
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
using filaflat::ChunkContainer;
|
||||
@@ -145,8 +132,10 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
||||
filaflat::ShaderContent content;
|
||||
extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content);
|
||||
|
||||
std::string const shader = mFormatter.format((char const*) content.data());
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_write(conn, content.data(), content.size() - 1);
|
||||
mg_write(conn, shader.c_str(), shader.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -171,12 +160,19 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
||||
extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content);
|
||||
|
||||
if (language == spirv) {
|
||||
spirvToAsm(conn, (uint32_t const*) content.data(), content.size());
|
||||
auto spirvDisassembly = ShaderExtractor::spirvToText((uint32_t const*) content.data(),
|
||||
content.size() / 4);
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (language == glsl) {
|
||||
spirvToGlsl(item.shaderModel, conn, (uint32_t const*) content.data(), content.size());
|
||||
auto glsl = ShaderExtractor::spirvToGLSL(item.shaderModel,
|
||||
(uint32_t const*) content.data(), content.size() / 4);
|
||||
std::string const shader = mFormatter.format((char const*) glsl.c_str());
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_printf(conn, shader.c_str(), shader.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -204,8 +200,9 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
||||
extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content);
|
||||
|
||||
if (language == msl) {
|
||||
std::string const shader = mFormatter.format((char const*) content.data());
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||
mg_write(conn, content.data(), content.size() - 1);
|
||||
mg_write(conn, shader.c_str(), shader.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef MATDBG_APIHANDLER_H
|
||||
#define MATDBG_APIHANDLER_H
|
||||
|
||||
#include "SourceFormatter.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
@@ -63,6 +65,8 @@ private:
|
||||
// will always block until statusMaterialId is updated again. The client is expected to keep
|
||||
// calling /api/status (a constant "pull" to simulate a push).
|
||||
std::atomic<uint64_t> mCurrentStatus = 0;
|
||||
|
||||
SourceFormatter mFormatter;
|
||||
};
|
||||
|
||||
} // filament::matdbg
|
||||
|
||||
@@ -193,8 +193,12 @@ DebugServer::addMaterial(const CString& name, const void* data, size_t size, voi
|
||||
return {};
|
||||
}
|
||||
|
||||
const uint32_t seed = 42;
|
||||
const MaterialKey key = utils::hash::murmurSlow((const uint8_t*) data, size, seed);
|
||||
// Note that it's possible to have two materials with the exact same content (however wasteful),
|
||||
// but they refer to different instantiation of FMaterial. Hence we hash on userdata and the
|
||||
// material data.
|
||||
constexpr uint32_t seed = 42;
|
||||
uint64_t dataSpace[2] = {(uint64_t) data, (uint64_t) userdata};
|
||||
uint32_t const key = utils::hash::murmurSlow((uint8_t const*) dataSpace, sizeof(dataSpace), seed);
|
||||
|
||||
// Retain a copy of the package to permit queries after the client application has
|
||||
// freed up the original material package.
|
||||
|
||||
@@ -377,7 +377,7 @@ void BlobIndex::writeChunks(ostream& stream) {
|
||||
for (auto& record : mShaderRecords) {
|
||||
const auto& src = mDataBlobs[record.dictionaryIndex];
|
||||
assert(src.size() % 4 == 0);
|
||||
const uint32_t* ptr = (const uint32_t*) src.data();
|
||||
uint8_t const* ptr = (uint8_t const*) src.data();
|
||||
record.dictionaryIndex = blobs.addBlob(vector<uint8_t>(ptr, ptr + src.size()));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 "SourceFormatter.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
namespace filament::matdbg {
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
std::string SourceFormatter::format(char const* source) {
|
||||
std::string const TMP_FILENAME = "/tmp/matdbg-tmp-src.cpp";
|
||||
|
||||
std::string original(source);
|
||||
FILE* fp;
|
||||
fp = fopen(TMP_FILENAME.c_str(), "w");
|
||||
if (!fp) {
|
||||
return original;
|
||||
}
|
||||
fputs(original.c_str(), fp);
|
||||
fflush(fp);
|
||||
pclose(fp);
|
||||
|
||||
std::string const CLANG_FORMAT_OPTIONS =
|
||||
"-style='{"
|
||||
"BasedOnStyle: Google, "
|
||||
"IndentWidth: 4, "
|
||||
"MaxEmptyLinesToKeep: 2"
|
||||
"}'";
|
||||
|
||||
fp = popen(("clang-format " + CLANG_FORMAT_OPTIONS + "< " + TMP_FILENAME).c_str(), "r");
|
||||
|
||||
if (!fp) {
|
||||
std::call_once(mClangWarningFlag, []() {
|
||||
utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
|
||||
<< "Please make sure it's installed.";
|
||||
});
|
||||
return original;
|
||||
}
|
||||
|
||||
char output[1024];
|
||||
std::stringstream outStream;
|
||||
while (fgets(output, 1024, fp) != NULL) {
|
||||
outStream << output;
|
||||
}
|
||||
|
||||
int status = pclose(fp);
|
||||
if (WEXITSTATUS(status)) {
|
||||
utils::slog.w << "[matdbg] clang-format failed with code=" << WEXITSTATUS(status)
|
||||
<< utils::io::endl;
|
||||
}
|
||||
return outStream.str();
|
||||
}
|
||||
#else
|
||||
std::string SourceFormatter::format(char const* source) {
|
||||
std::call_once(mClangWarningFlag, []() {
|
||||
utils::slog.w <<"[matdbg]: source formatting is not available on this platform" <<
|
||||
utils::io::endl;
|
||||
});
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
} // filament::matdbg
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MATDBG_SOURCE_FORMATTER_H
|
||||
#define MATDBG_SOURCE_FORMATTER_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace filament::matdbg {
|
||||
|
||||
class SourceFormatter {
|
||||
public:
|
||||
SourceFormatter() = default;
|
||||
~SourceFormatter() = default;
|
||||
std::string format(char const* source);
|
||||
|
||||
private:
|
||||
|
||||
std::once_flag mClangWarningFlag;
|
||||
};
|
||||
|
||||
} // filament::matdbg
|
||||
|
||||
#endif // MATDBG_SOURCE_FORMATTER_H
|
||||
+87
-13
@@ -452,6 +452,7 @@ class AdvancedOptions extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
availableBackends: {type: Array, state: true},
|
||||
};
|
||||
}
|
||||
@@ -470,6 +471,9 @@ class AdvancedOptions extends LitElement {
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.borderless {
|
||||
border: 1px solid rgba(0,0,0,0);
|
||||
}
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -486,6 +490,35 @@ class AdvancedOptions extends LitElement {
|
||||
.option-heading {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Below is a custom checkbox */
|
||||
input[type="checkbox"] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background-color: var(--form-background);
|
||||
margin-right: 5px;
|
||||
font: inherit;
|
||||
width: 1.15em;
|
||||
height: 1.15em;
|
||||
border: 0.15em solid ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
border-radius: 0.15em;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
input[type="checkbox"]::before {
|
||||
content: "";
|
||||
width: 0.65em;
|
||||
height: 0.65em;
|
||||
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
|
||||
transform: scale(0);
|
||||
transform-origin: bottom left;
|
||||
box-shadow: inset 1em 1em var(--form-control-color);
|
||||
/* Windows High Contrast Mode */
|
||||
background-color: ${unsafeCSS(FOREGROUND_COLOR)};
|
||||
}
|
||||
input[type="checkbox"]:checked::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -536,6 +569,25 @@ class AdvancedOptions extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
_hideInactiveVariantsOption() {
|
||||
const onChange = (ev) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(
|
||||
'option-hide-inactive-variants',
|
||||
{detail: null, bubbles: true, composed: true}));
|
||||
}
|
||||
return html`
|
||||
<div class="option borderless">
|
||||
<!--<div class="option-heading">Current Backend</div>-->
|
||||
<form action="" id="hide-inactive-variants-form">
|
||||
<input type="checkbox" name="InactiveVariants"
|
||||
?checked=${this.hideInactiveVariants} @change=${onChange}/>
|
||||
Hide Inactive Variants
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.availableBackends = [];
|
||||
@@ -544,6 +596,7 @@ class AdvancedOptions extends LitElement {
|
||||
render() {
|
||||
return html`
|
||||
<menu-section title="Advanced Options">
|
||||
${this._hideInactiveVariantsOption() ?? nothing}
|
||||
${this._backendOption() ?? nothing}
|
||||
</menu-section>
|
||||
`;
|
||||
@@ -613,11 +666,11 @@ class MaterialSidePanel extends LitElement {
|
||||
currentShaderIndex: {type: Number, attribute: 'current-shader-index'},
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
currentLanguage: {type: String, attribute: 'current-language'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
|
||||
database: {type: Object, state: true},
|
||||
materials: {type: Array, state: true},
|
||||
activeShaders: {type: Object, state: true},
|
||||
|
||||
variants: {type: Array, state: true},
|
||||
}
|
||||
}
|
||||
@@ -662,8 +715,8 @@ class MaterialSidePanel extends LitElement {
|
||||
let name = material.name || kUntitledPlaceholder;
|
||||
if (name in duplicatedLabels) {
|
||||
const index = duplicatedLabels[name];
|
||||
name = `${name} (${index})`;
|
||||
duplicatedLabels[name] = index + 1;
|
||||
name = `${name} (${index})`;
|
||||
}
|
||||
return {
|
||||
matid: matid,
|
||||
@@ -747,6 +800,7 @@ class MaterialSidePanel extends LitElement {
|
||||
if (b.active && !a.active) return 1;
|
||||
return 0;
|
||||
})
|
||||
.filter((variant) => (!this.hideInactiveVariants || variant.shader.active))
|
||||
.map((variant) => {
|
||||
let divClass = 'material_variant_language';
|
||||
const shaderIndex = +variant.shader.index;
|
||||
@@ -778,7 +832,13 @@ class MaterialSidePanel extends LitElement {
|
||||
|
||||
render() {
|
||||
const sections = (title, domain) => {
|
||||
const mats = this.materials.filter((m) => m.domain == domain).map((mat) => {
|
||||
const mats = this.materials
|
||||
.filter((m) => m.domain == domain)
|
||||
.filter((mat) => {
|
||||
const material = this.database[mat.matid];
|
||||
return !this.hideInactiveVariants || material.active;
|
||||
})
|
||||
.map((mat) => {
|
||||
const material = this.database[mat.matid];
|
||||
const onClick = this._handleMaterialClick.bind(this, mat.matid);
|
||||
let divClass = 'material_variant_language';
|
||||
@@ -806,15 +866,13 @@ class MaterialSidePanel extends LitElement {
|
||||
}
|
||||
return null;
|
||||
};
|
||||
let advancedOptions = null;
|
||||
// Currently we only have one advanced option and it's only for when we're in matinfo
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
advancedOptions =
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}></advanced-options>
|
||||
`)();
|
||||
}
|
||||
const advancedOptions =
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}
|
||||
?hide-inactive-variants=${this.hideInactiveVariants}
|
||||
></advanced-options>
|
||||
`)();
|
||||
|
||||
return html`
|
||||
<style>${this.dynamicStyle()}</style>
|
||||
@@ -874,6 +932,12 @@ class MatdbgViewer extends LitElement {
|
||||
|
||||
let materials = await fetchMaterials();
|
||||
this.database = materials;
|
||||
|
||||
// This is the user preferences stored in localStorage
|
||||
let hideInactiveVariantsVal = localStorage.getItem('option-hide-inactive-variants');
|
||||
if (hideInactiveVariantsVal != null) {
|
||||
this.hideInactiveVariants = hideInactiveVariantsVal == 'true';
|
||||
}
|
||||
}
|
||||
|
||||
_getShader() {
|
||||
@@ -907,6 +971,7 @@ class MatdbgViewer extends LitElement {
|
||||
this.currentMaterial = null;
|
||||
this.currentLanguage = null;
|
||||
this.currentBackend = null;
|
||||
this.hideInactiveVariants = false;
|
||||
this.init();
|
||||
|
||||
this.addEventListener('select-material',
|
||||
@@ -957,6 +1022,12 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
this.addEventListener('option-hide-inactive-variants',
|
||||
(ev) => {
|
||||
this.hideInactiveVariants = !this.hideInactiveVariants;
|
||||
localStorage.setItem('option-hide-inactive-variants', "" + this.hideInactiveVariants);
|
||||
}
|
||||
);
|
||||
addEventListener('resize', this._onResize.bind(this));
|
||||
}
|
||||
|
||||
@@ -972,6 +1043,8 @@ class MatdbgViewer extends LitElement {
|
||||
currentBackend: {type: String, state: true},
|
||||
codeViewerExpectedWidth: {type: Number, state: true},
|
||||
codeViewerExpectedHeight: {type: Number, state: true},
|
||||
|
||||
hideInactiveVariants: {type: Boolean, state: true},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,7 +1158,8 @@ class MatdbgViewer extends LitElement {
|
||||
current-language="${this.currentLanguage}"
|
||||
current-shader-index="${this.currentShaderIndex}"
|
||||
current-material="${this.currentMaterial}"
|
||||
current-backend="${this.currentBackend}" >
|
||||
current-backend="${this.currentBackend}"
|
||||
?hide-inactive-variants="${this.hideInactiveVariants}" >
|
||||
</material-sidepanel>
|
||||
<code-viewer id="code-viewer"
|
||||
?active=${shader && shader.active}
|
||||
|
||||
@@ -158,7 +158,7 @@ static void printUsage(char* name) {
|
||||
" Specify the backend API: "
|
||||
|
||||
// Matches logic in filament/backend/src/PlatformFactory.cpp for Backend::DEFAULT
|
||||
#if defined(IOS) || defined(__APPLE__)
|
||||
#if defined(FILAMENT_IOS) || defined(__APPLE__)
|
||||
"opengl, vulkan, or metal (default)"
|
||||
#elif defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
"opengl, vulkan (default), or metal"
|
||||
|
||||
Vendored
+1
-1
@@ -13,7 +13,7 @@ set(CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS
|
||||
# Necessary for correct install location
|
||||
set(DIST_ARCH ${IOS_ARCH})
|
||||
|
||||
add_definitions(-DIOS)
|
||||
add_definitions(-DFILAMENT_IOS)
|
||||
|
||||
set(IOS_MIN_TARGET "11.0")
|
||||
|
||||
|
||||
@@ -1489,6 +1489,8 @@ class_<TexBuilder>("Texture$Builder")
|
||||
return &builder->sampler(target); })
|
||||
.BUILDER_FUNCTION("format", TexBuilder, (TexBuilder* builder, Texture::InternalFormat fmt), {
|
||||
return &builder->format(fmt); })
|
||||
.BUILDER_FUNCTION("external", TexBuilder, (TexBuilder* builder), {
|
||||
return &builder->external(); })
|
||||
|
||||
// This takes a bitfield that can be composed by or'ing constants.
|
||||
// - JS clients should use the value member, as in: "Texture$Usage.SAMPLEABLE.value".
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.56.4",
|
||||
"version": "1.56.5",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user