Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fc8e339e7 | ||
|
|
0395df3689 | ||
|
|
64f03b3832 | ||
|
|
982b159b3e | ||
|
|
e95edef9d7 | ||
|
|
9cfef925bb | ||
|
|
3900fc6c37 | ||
|
|
b8ec1658f3 | ||
|
|
371bd1f01f | ||
|
|
6e3cccf30c | ||
|
|
df34f92f8f | ||
|
|
43331d04e5 | ||
|
|
9917d4b7d9 | ||
|
|
682150ceec | ||
|
|
af2ecf201f | ||
|
|
020668733a | ||
|
|
4c6d653d60 | ||
|
|
d1022527ac | ||
|
|
68c7a6c7b6 | ||
|
|
f077fff012 | ||
|
|
bea02427ed | ||
|
|
b5d7de06bc | ||
|
|
749b063af3 | ||
|
|
7aefa99e06 |
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: npm-deploy
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ github.event.inputs.release_tag }}
|
||||
# Setup .npmrc file to publish to npm
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
os: [macos-14, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat presubmit
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh presubmit
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh presubmit
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: actions/setup-java@v3
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.52.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.53.1'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.52.3'
|
||||
pod 'Filament', '~> 1.53.1'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -7,6 +7,13 @@ 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.53.1
|
||||
|
||||
|
||||
## v1.53.0
|
||||
|
||||
- engine: fix skinning normals with large transforms (b/342459864) [⚠️ **New Material Version**]
|
||||
|
||||
## v1.52.3
|
||||
|
||||
|
||||
|
||||
@@ -83,12 +83,12 @@ buildscript {
|
||||
'minSdk': 21,
|
||||
'targetSdk': 34,
|
||||
'compileSdk': 34,
|
||||
'kotlin': '1.9.21',
|
||||
'kotlin_coroutines': '1.7.3',
|
||||
'kotlin': '2.0.0',
|
||||
'kotlin_coroutines': '1.9.0-RC',
|
||||
'buildTools': '34.0.0',
|
||||
'ndk': '26.1.10909125',
|
||||
'androidx_core': '1.12.0',
|
||||
'androidx_annotations': '1.7.0'
|
||||
'ndk': '27.0.11718014',
|
||||
'androidx_core': '1.13.1',
|
||||
'androidx_annotations': '1.8.0'
|
||||
]
|
||||
|
||||
ext.deps = [
|
||||
@@ -104,7 +104,7 @@ buildscript {
|
||||
]
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.2.0'
|
||||
classpath 'com.android.tools.build:gradle:8.4.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
|
||||
}
|
||||
|
||||
|
||||
@@ -420,6 +420,13 @@ Java_com_google_android_filament_Engine_nSetPaused(JNIEnv*, jclass,
|
||||
engine->setPaused(paused);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nUnprotected(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jboolean paused) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->unprotected();
|
||||
}
|
||||
|
||||
// Managers...
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
|
||||
@@ -1289,6 +1289,18 @@ public class Engine {
|
||||
nSetPaused(getNativeObject(), paused);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the command queue to unprotected mode. Protected mode can be activated via
|
||||
* Renderer::beginFrame() using a protected SwapChain.
|
||||
|
||||
* @see Renderer
|
||||
* @see SwapChain
|
||||
*/
|
||||
public void unprotected() {
|
||||
nUnprotected(getNativeObject());
|
||||
}
|
||||
|
||||
|
||||
@UsedByReflection("TextureHelper.java")
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
@@ -1366,6 +1378,7 @@ public class Engine {
|
||||
private static native void nFlush(long nativeEngine);
|
||||
private static native boolean nIsPaused(long nativeEngine);
|
||||
private static native void nSetPaused(long nativeEngine, boolean paused);
|
||||
private static native void nUnprotected(long nativeEngine);
|
||||
private static native long nGetTransformManager(long nativeEngine);
|
||||
private static native long nGetLightManager(long nativeEngine);
|
||||
private static native long nGetRenderableManager(long nativeEngine);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.52.3
|
||||
VERSION_NAME=1.53.1
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 17 10:40:18 PST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -57,7 +57,8 @@ FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
|
||||
|
||||
# Install the required NDK version specifically (if not present)
|
||||
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
||||
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION" > /dev/null
|
||||
yes | ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --licenses
|
||||
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION"
|
||||
fi
|
||||
|
||||
# Only build 1 64 bit target during presubmit to cut down build times during presubmit
|
||||
|
||||
@@ -1 +1 @@
|
||||
26.1.10909125
|
||||
27.0.11718014
|
||||
@@ -90,8 +90,13 @@ protected:
|
||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
||||
|
||||
private:
|
||||
struct InitializeJvmForPerformanceManagerIfNeeded {
|
||||
InitializeJvmForPerformanceManagerIfNeeded();
|
||||
};
|
||||
|
||||
int mOSVersion;
|
||||
ExternalStreamManagerAndroid& mExternalStreamManager;
|
||||
InitializeJvmForPerformanceManagerIfNeeded const mInitializeJvmForPerformanceManagerIfNeeded;
|
||||
utils::PerformanceHintManager mPerformanceHintManager;
|
||||
utils::PerformanceHintManager::Session mPerformanceHintSession;
|
||||
|
||||
|
||||
@@ -90,6 +90,20 @@ public:
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
struct ImageSyncData {
|
||||
static constexpr uint32_t INVALID_IMAGE_INDEX = UINT32_MAX;
|
||||
|
||||
// The index of the next image as returned by vkAcquireNextImage or equivalent.
|
||||
uint32_t imageIndex = INVALID_IMAGE_INDEX;
|
||||
|
||||
// Semaphore to be signaled once the image is available.
|
||||
VkSemaphore imageReadySemaphore = VK_NULL_HANDLE;
|
||||
|
||||
// A function called right before vkQueueSubmit. After this call, the image must be
|
||||
// available. This pointer can be null if imageReadySemaphore is not VK_NULL_HANDLE.
|
||||
std::function<void(SwapChainPtr handle)> explicitImageReadyWait = nullptr;
|
||||
};
|
||||
|
||||
VulkanPlatform();
|
||||
|
||||
~VulkanPlatform() override;
|
||||
@@ -127,6 +141,12 @@ public:
|
||||
* before recreating the swapchain. Default is true.
|
||||
*/
|
||||
bool flushAndWaitOnWindowResize = true;
|
||||
|
||||
/**
|
||||
* Whether the swapchain image should be transitioned to a layout suitable for
|
||||
* presentation. Default is true.
|
||||
*/
|
||||
bool transitionSwapChainImageLayoutForPresent = true;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -155,13 +175,10 @@ public:
|
||||
* corresponding VkImage will be used as the output color attachment. The client should signal
|
||||
* the `clientSignal` semaphore when the image is ready to be used by the backend.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @param clientSignal The semaphore that the client will signal to indicate that the backend
|
||||
* may render into the image.
|
||||
* @param index Pointer to memory that will be filled with the index that corresponding
|
||||
* to an image in the `SwapChainBundle.colors` array.
|
||||
* @param outImageSyncData The synchronization data used for image readiness
|
||||
* @return Result of acquire
|
||||
*/
|
||||
virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index);
|
||||
virtual VkResult acquire(SwapChainPtr handle, ImageSyncData* outImageSyncData);
|
||||
|
||||
/**
|
||||
* Present the image corresponding to `index` to the display. The client should wait on
|
||||
|
||||
@@ -16,13 +16,23 @@
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr;
|
||||
|
||||
// This is called when the library is loaded. We need this to get a reference to the global VM
|
||||
/*
|
||||
* This is typically called by filament_jni.so when it is loaded. If filament_jni.so is not used,
|
||||
* then this must be called manually -- however, this is a problem because VirtualMachineEnv.h
|
||||
* is currently private and part of backend.
|
||||
* For now, we authorize this usage, but we will need to fix it; by making a proper public
|
||||
* API for this.
|
||||
*/
|
||||
UTILS_PUBLIC
|
||||
UTILS_NOINLINE
|
||||
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept {
|
||||
JNIEnv* env = nullptr;
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
NSUInteger headlessWidth = 0;
|
||||
NSUInteger headlessHeight = 0;
|
||||
CAMetalLayer* layer = nullptr;
|
||||
std::mutex layerDrawableMutex;
|
||||
std::shared_ptr<std::mutex> layerDrawableMutex;
|
||||
MetalExternalImage externalImage;
|
||||
SwapChainType type;
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
|
||||
: context(context),
|
||||
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||
layer(nativeWindow),
|
||||
layerDrawableMutex(std::make_shared<std::mutex>()),
|
||||
externalImage(context),
|
||||
type(SwapChainType::CAMETALLAYER) {
|
||||
|
||||
@@ -179,7 +180,7 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
// calling -nextDrawable, or when releasing the last known reference
|
||||
// to any CAMetalDrawable returned from a previous -nextDrawable.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(layerDrawableMutex);
|
||||
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
|
||||
drawable = [layer nextDrawable];
|
||||
}
|
||||
|
||||
@@ -188,8 +189,10 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
}
|
||||
|
||||
void MetalSwapChain::releaseDrawable() {
|
||||
std::lock_guard<std::mutex> lock(layerDrawableMutex);
|
||||
drawable = nil;
|
||||
if (drawable) {
|
||||
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
|
||||
drawable = nil;
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
|
||||
@@ -265,7 +268,7 @@ public:
|
||||
PresentDrawableData& operator=(const PresentDrawableData&) = delete;
|
||||
|
||||
static PresentDrawableData* create(id<CAMetalDrawable> drawable,
|
||||
std::mutex* drawableMutex, MetalDriver* driver) {
|
||||
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver) {
|
||||
assert_invariant(drawableMutex);
|
||||
assert_invariant(driver);
|
||||
return new PresentDrawableData(drawable, drawableMutex, driver);
|
||||
@@ -287,22 +290,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PresentDrawableData(id<CAMetalDrawable> drawable, std::mutex* drawableMutex,
|
||||
PresentDrawableData(id<CAMetalDrawable> drawable, std::shared_ptr<std::mutex> drawableMutex,
|
||||
MetalDriver* driver)
|
||||
: mDrawable(drawable), mDrawableMutex(drawableMutex), mDriver(driver) {}
|
||||
|
||||
static void cleanupAndDestroy(PresentDrawableData *that) {
|
||||
{
|
||||
if (that->mDrawable) {
|
||||
std::lock_guard<std::mutex> lock(*(that->mDrawableMutex));
|
||||
that->mDrawable = nil;
|
||||
}
|
||||
that->mDrawableMutex = nullptr;
|
||||
that->mDrawableMutex.reset();
|
||||
that->mDriver = nullptr;
|
||||
delete that;
|
||||
}
|
||||
|
||||
id<CAMetalDrawable> mDrawable;
|
||||
std::mutex* mDrawableMutex = nullptr;
|
||||
std::shared_ptr<std::mutex> mDrawableMutex;
|
||||
MetalDriver* mDriver = nullptr;
|
||||
};
|
||||
|
||||
@@ -320,7 +323,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
|
||||
|
||||
struct Callback {
|
||||
Callback(std::shared_ptr<FrameScheduledCallback> callback, id<CAMetalDrawable> drawable,
|
||||
std::mutex* drawableMutex, MetalDriver* driver)
|
||||
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver)
|
||||
: f(callback), data(PresentDrawableData::create(drawable, drawableMutex, driver)) {}
|
||||
std::shared_ptr<FrameScheduledCallback> f;
|
||||
// PresentDrawableData* is destroyed by maybePresentAndDestroyAsync() later.
|
||||
@@ -337,7 +340,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
|
||||
// This callback pointer will be captured by the block. Even if the scheduled handler is never
|
||||
// called, the unique_ptr will still ensure we don't leak memory.
|
||||
__block auto callback = std::make_unique<Callback>(
|
||||
frameScheduled.callback, drawable, &layerDrawableMutex, context.driver);
|
||||
frameScheduled.callback, drawable, layerDrawableMutex, context.driver);
|
||||
|
||||
backend::CallbackHandler* handler = frameScheduled.handler;
|
||||
MetalDriver* driver = context.driver;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <backend/platforms/PlatformEGL.h>
|
||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
||||
|
||||
#include <private/backend/VirtualMachineEnv.h>
|
||||
|
||||
#include "opengl/GLUtils.h"
|
||||
#include "ExternalStreamManagerAndroid.h"
|
||||
|
||||
@@ -82,9 +84,23 @@ using EGLStream = Platform::Stream;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
PlatformEGLAndroid::InitializeJvmForPerformanceManagerIfNeeded::InitializeJvmForPerformanceManagerIfNeeded() {
|
||||
// PerformanceHintManager() needs the calling thread to be a Java thread; so we need
|
||||
// to attach this thread to the JVM before we initialize PerformanceHintManager.
|
||||
// This should be done in PerformanceHintManager(), but libutils doesn't have access to
|
||||
// VirtualMachineEnv.
|
||||
if (PerformanceHintManager::isSupported()) {
|
||||
(void)VirtualMachineEnv::get().getEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
|
||||
: PlatformEGL(),
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::create()) {
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::create()),
|
||||
mInitializeJvmForPerformanceManagerIfNeeded(),
|
||||
mPerformanceHintManager() {
|
||||
|
||||
char scratch[PROP_VALUE_MAX + 1];
|
||||
int length = __system_property_get("ro.build.version.release", scratch);
|
||||
|
||||
@@ -37,7 +37,7 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
VulkanAttachment src, VulkanAttachment dst,
|
||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
<< " layout=" << src.getLayout()
|
||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||
<< " layout=" << dst.getLayout() << utils::io::endl;
|
||||
@@ -76,7 +76,7 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
inline void resolveFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
VulkanAttachment src, VulkanAttachment dst) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
<< " layout=" << src.getLayout()
|
||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||
<< " layout=" << dst.getLayout() << utils::io::endl;
|
||||
|
||||
@@ -178,7 +178,7 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
||||
// presenting the swap chain or waiting on a fence.
|
||||
while (mAvailableBufferCount == 0) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "VulkanCommands has stalled. "
|
||||
FVK_LOGI << "VulkanCommands has stalled. "
|
||||
<< "If this occurs frequently, consider increasing VK_MAX_COMMAND_BUFFERS."
|
||||
<< io::endl;
|
||||
#endif
|
||||
@@ -289,7 +289,7 @@ bool VulkanCommands::flush() {
|
||||
};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
||||
FVK_LOGI << "Submitting cmdbuffer=" << cmdbuffer
|
||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||
<< " signal=" << renderingFinished
|
||||
<< " fence=" << currentbuf->fence->fence
|
||||
@@ -305,7 +305,7 @@ bool VulkanCommands::flush() {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.d << "Failed command buffer submission result: " << result << utils::io::endl;
|
||||
FVK_LOGD << "Failed command buffer submission result: " << result << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
assert_invariant(result == VK_SUCCESS);
|
||||
@@ -320,7 +320,7 @@ VkSemaphore VulkanCommands::acquireFinishedSignal() {
|
||||
VkSemaphore semaphore = mSubmissionSignal;
|
||||
mSubmissionSignal = VK_NULL_HANDLE;
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
FVK_LOGI << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
#endif
|
||||
return semaphore;
|
||||
}
|
||||
@@ -329,7 +329,7 @@ void VulkanCommands::injectDependency(VkSemaphore next) {
|
||||
assert_invariant(mInjectedSignal == VK_NULL_HANDLE);
|
||||
mInjectedSignal = next;
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Injecting " << next << " (e.g. due to vkAcquireNextImageKHR)" << io::endl;
|
||||
FVK_LOGI << "Injecting " << next << " (e.g. due to vkAcquireNextImageKHR)" << io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
|
||||
// If the timestamp is not 0, then we are carrying over a marker across buffer submits.
|
||||
// If it is 0, then this is a normal marker push and we should just print debug line as usual.
|
||||
if (timestamp.time_since_epoch().count() == 0.0) {
|
||||
utils::slog.d << "----> " << str << utils::io::endl;
|
||||
FVK_LOGD << "----> " << str << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -436,7 +436,7 @@ void VulkanCommands::popGroupMarker() {
|
||||
auto const [marker, startTime] = mGroupMarkers->pop();
|
||||
auto const endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = endTime - startTime;
|
||||
utils::slog.d << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
|
||||
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
|
||||
<< utils::io::endl;
|
||||
#else
|
||||
mGroupMarkers->pop();
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// In debug builds, we enable validation layers and set up a debug callback.
|
||||
@@ -70,6 +72,11 @@
|
||||
// the currently active resources.
|
||||
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
|
||||
|
||||
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
|
||||
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
|
||||
// order of calls).
|
||||
#define FVK_DEBUG_FORCE_LOG_TO_I 0x00020000
|
||||
|
||||
// Useful default combinations
|
||||
#define FVK_DEBUG_EVERYTHING 0xFFFFFFFF
|
||||
#define FVK_DEBUG_PERFORMANCE \
|
||||
@@ -133,6 +140,18 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
|
||||
#define FVK_HANDLE_ARENA_SIZE_IN_MB 8
|
||||
#endif
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FORCE_LOG_TO_I)
|
||||
#define FVK_LOGI (utils::slog.i)
|
||||
#define FVK_LOGD FVK_LOGI
|
||||
#define FVK_LOGE FVK_LOGI
|
||||
#define FVK_LOGW FVK_LOGI
|
||||
#else
|
||||
#define FVK_LOGE (utils::slog.e)
|
||||
#define FVK_LOGW (utils::slog.w)
|
||||
#define FVK_LOGD (utils::slog.d)
|
||||
#define FVK_LOGI (utils::slog.i)
|
||||
#endif
|
||||
|
||||
// All vkCreate* functions take an optional allocator. For now we select the default allocator by
|
||||
// passing in a null pointer, and we highlight the argument by using the VKALLOC constant.
|
||||
constexpr struct VkAllocationCallbacks* VKALLOC = nullptr;
|
||||
|
||||
@@ -100,7 +100,7 @@ std::tuple<uint32_t, uint32_t> VulkanTimestamps::getNextQuery() {
|
||||
return std::make_tuple(timerIndex * 2, timerIndex * 2 + 1);
|
||||
}
|
||||
}
|
||||
utils::slog.e << "More than " << maxTimers << " timers are not supported." << utils::io::endl;
|
||||
FVK_LOGE << "More than " << maxTimers << " timers are not supported." << utils::io::endl;
|
||||
return std::make_tuple(0, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,10 @@ public:
|
||||
return mDebugUtilsSupported;
|
||||
}
|
||||
|
||||
inline bool isMultiviewEnabled() const noexcept {
|
||||
return mMultiviewEnabled;
|
||||
}
|
||||
|
||||
inline bool isClipDistanceSupported() const noexcept {
|
||||
return mPhysicalDeviceFeatures.shaderClipDistance == VK_TRUE;
|
||||
}
|
||||
@@ -141,6 +145,7 @@ private:
|
||||
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures = {};
|
||||
bool mDebugMarkersSupported = false;
|
||||
bool mDebugUtilsSupported = false;
|
||||
bool mMultiviewEnabled = false;
|
||||
|
||||
VkFormatList mDepthStencilFormats;
|
||||
VkFormatList mBlittableDepthStencilFormats;
|
||||
|
||||
@@ -115,15 +115,15 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags,
|
||||
VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location,
|
||||
int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) {
|
||||
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
||||
utils::slog.e << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
} else {
|
||||
// TODO: emit best practices warnings about aggressive pipeline barriers.
|
||||
if (strstr(pMessage, "ALL_GRAPHICS_BIT") || strstr(pMessage, "ALL_COMMANDS_BIT")) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
utils::slog.w << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
}
|
||||
utils::slog.e << utils::io::endl;
|
||||
FVK_LOGE << utils::io::endl;
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
||||
@@ -133,18 +133,18 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
|
||||
VkDebugUtilsMessageTypeFlagsEXT types, const VkDebugUtilsMessengerCallbackDataEXT* cbdata,
|
||||
void* pUserData) {
|
||||
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
utils::slog.e << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
} else {
|
||||
// TODO: emit best practices warnings about aggressive pipeline barriers.
|
||||
if (strstr(cbdata->pMessage, "ALL_GRAPHICS_BIT")
|
||||
|| strstr(cbdata->pMessage, "ALL_COMMANDS_BIT")) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
utils::slog.w << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
}
|
||||
utils::slog.e << utils::io::endl;
|
||||
FVK_LOGE << utils::io::endl;
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
@@ -292,7 +292,7 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont
|
||||
// VulkanRenderTarget : 312 few
|
||||
// -- less than or equal to 312 bytes
|
||||
|
||||
utils::slog.d
|
||||
FVK_LOGD
|
||||
<< "\nVulkanSwapChain: " << sizeof(VulkanSwapChain)
|
||||
<< "\nVulkanBufferObject: " << sizeof(VulkanBufferObject)
|
||||
<< "\nVulkanVertexBuffer: " << sizeof(VulkanVertexBuffer)
|
||||
@@ -397,7 +397,10 @@ void VulkanDriver::collectGarbage() {
|
||||
}
|
||||
void VulkanDriver::beginFrame(int64_t monotonic_clock_ns,
|
||||
int64_t refreshIntervalNs, uint32_t frameId) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("beginFrame");
|
||||
// Do nothing.
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
||||
@@ -657,8 +660,8 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
|
||||
|
||||
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
||||
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||
}
|
||||
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
|
||||
@@ -669,7 +672,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
||||
uint32_t height, uint64_t flags) {
|
||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
||||
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
||||
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||
}
|
||||
@@ -911,7 +914,7 @@ bool VulkanDriver::isStereoSupported() {
|
||||
case backend::StereoscopicType::INSTANCED:
|
||||
return mContext.isClipDistanceSupported();
|
||||
case backend::StereoscopicType::MULTIVIEW:
|
||||
// TODO: implement multiview feature in Vulkan.
|
||||
return mContext.isMultiviewEnabled();
|
||||
case backend::StereoscopicType::NONE:
|
||||
return false;
|
||||
}
|
||||
@@ -1859,9 +1862,9 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
// matching characteristics. (e.g. if the missing texture is a 3D texture)
|
||||
if (UTILS_UNLIKELY(texture->getPrimaryImageLayout() == VulkanLayout::UNDEFINED)) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE) && FVK_ENABLED_DEBUG_SAMPLER_NAME
|
||||
utils::slog.w << "Uninitialized texture bound to '" << bindingToName[binding] << "'";
|
||||
utils::slog.w << " in material '" << program->name.c_str() << "'";
|
||||
utils::slog.w << " at binding point " << +binding << utils::io::endl;
|
||||
FVK_LOGW << "Uninitialized texture bound to '" << bindingToName[binding] << "'";
|
||||
FVK_LOGW << " in material '" << program->name.c_str() << "'";
|
||||
FVK_LOGW << " at binding point " << +binding << utils::io::endl;
|
||||
#endif
|
||||
texture = mEmptyTexture;
|
||||
}
|
||||
@@ -2011,7 +2014,7 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
|
||||
assert_invariant(inRenderPass);
|
||||
inRenderPass = false;
|
||||
} else if (inRenderPass && OUTSIDE_COMMANDS.find(command) != OUTSIDE_COMMANDS.end()) {
|
||||
utils::slog.e << command.data() << " issued inside a render pass." << utils::io::endl;
|
||||
FVK_LOGE << command.data() << " issued inside a render pass." << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ VkFramebuffer VulkanFboCache::getFramebuffer(FboKey config) noexcept {
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Creating framebuffer " << config.width << "x" << config.height << " "
|
||||
FVK_LOGD << "Creating framebuffer " << config.width << "x" << config.height << " "
|
||||
<< "for render pass " << config.renderPass << ", "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
<< "depth = " << (config.depth ? 1 : 0) << ", "
|
||||
@@ -310,7 +310,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
|
||||
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Created render pass " << renderPass << " with "
|
||||
FVK_LOGD << "Created render pass " << renderPass << " with "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
<< "depth = " << (hasDepth ? 1 : 0) << ", "
|
||||
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
|
||||
|
||||
@@ -292,8 +292,8 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "Created VulkanProgram " << builder << ", shaders = (" << modules[0]
|
||||
<< ", " << modules[1] << ")" << utils::io::endl;
|
||||
FVK_LOGD << "Created VulkanProgram " << builder << ", shaders = (" << modules[0]
|
||||
<< ", " << modules[1] << ")" << utils::io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -230,14 +230,15 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
PipelineCacheEntry cacheEntry = {};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "vkCreateGraphicsPipelines with shaders = ("
|
||||
<< shaderStages[0].module << ", " << shaderStages[1].module << ")" << utils::io::endl;
|
||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = ("
|
||||
<< shaderStages[0].module << ", " << shaderStages[1].module << ")"
|
||||
<< utils::io::endl;
|
||||
#endif
|
||||
VkResult error = vkCreateGraphicsPipelines(mDevice, VK_NULL_HANDLE, 1, &pipelineCreateInfo,
|
||||
VKALLOC, &cacheEntry.handle);
|
||||
assert_invariant(error == VK_SUCCESS);
|
||||
if (error != VK_SUCCESS) {
|
||||
utils::slog.e << "vkCreateGraphicsPipelines error " << error << utils::io::endl;
|
||||
FVK_LOGE << "vkCreateGraphicsPipelines error " << error << utils::io::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -252,7 +253,7 @@ void VulkanPipelineCache::bindProgram(VulkanProgram* program) noexcept {
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
if (mPipelineRequirements.shaders[0] == VK_NULL_HANDLE ||
|
||||
mPipelineRequirements.shaders[1] == VK_NULL_HANDLE) {
|
||||
utils::slog.e << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
|
||||
FVK_LOGE << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -167,9 +167,9 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
vkCreateImage(device, &imageInfo, VKALLOC, &stagingImage);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_READ_PIXELS)
|
||||
utils::slog.d << "readPixels created image=" << stagingImage
|
||||
<< " to copy from image=" << srcTexture->getVkImage()
|
||||
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
|
||||
FVK_LOGD << "readPixels created image=" << stagingImage
|
||||
<< " to copy from image=" << srcTexture->getVkImage()
|
||||
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
|
||||
#endif
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
@@ -185,7 +185,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
if (memoryTypeIndex >= VK_MAX_MEMORY_TYPES) {
|
||||
memoryTypeIndex = selectMemoryFunc(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
utils::slog.w
|
||||
FVK_LOGW
|
||||
<< "readPixels is slow because VK_MEMORY_PROPERTY_HOST_CACHED_BIT is not available"
|
||||
<< utils::io::endl;
|
||||
}
|
||||
@@ -303,7 +303,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
VkResult status = vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||
// Fence hasn't been reached. Try waiting again.
|
||||
if (status != VK_SUCCESS) {
|
||||
utils::slog.e << "Failed to wait for readPixels fence" << utils::io::endl;
|
||||
FVK_LOGE << "Failed to wait for readPixels fence" << utils::io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
getComponentCount(srcFormat), srcPixels,
|
||||
static_cast<int>(subResourceLayout.rowPitch), static_cast<int>(width),
|
||||
static_cast<int>(height), swizzle)) {
|
||||
utils::slog.e << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
|
||||
FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
|
||||
}
|
||||
|
||||
vkUnmapMemory(device, stagingMemory);
|
||||
|
||||
@@ -111,11 +111,11 @@ private:
|
||||
#if DEBUG_RESOURCE_LEAKS
|
||||
public:
|
||||
void print() {
|
||||
utils::slog.d << "Resource Allocator state (debug only)" << utils::io::endl;
|
||||
FVK_LOGD << "Resource Allocator state (debug only)" << utils::io::endl;
|
||||
for (size_t i = 0; i < RESOURCE_TYPE_COUNT; i++) {
|
||||
utils::slog.d << "[" << i << "]=" << mDebugOnlyResourceCount[i] << utils::io::endl;
|
||||
FVK_LOGD << "[" << i << "]=" << mDebugOnlyResourceCount[i] << utils::io::endl;
|
||||
}
|
||||
utils::slog.d << "+++++++++++++++++++++++++++++++++++++" << utils::io::endl;
|
||||
FVK_LOGD << "+++++++++++++++++++++++++++++++++++++" << utils::io::endl;
|
||||
}
|
||||
private:
|
||||
utils::FixedCapacityVector<size_t> mDebugOnlyResourceCount;
|
||||
|
||||
@@ -61,7 +61,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_ALLOCATION)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.e << "Allocation error: " << result << utils::io::endl;
|
||||
FVK_LOGE << "Allocation error: " << result << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -35,29 +35,13 @@ VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const&
|
||||
mStagePool(stagePool),
|
||||
mHeadless(extent.width != 0 && extent.height != 0 && !nativeWindow),
|
||||
mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize),
|
||||
mCurrentImageReadyIndex(0),
|
||||
mTransitionSwapChainImageLayoutForPresent(
|
||||
platform->getCustomization().transitionSwapChainImageLayoutForPresent),
|
||||
mAcquired(false),
|
||||
mIsFirstRenderPass(true) {
|
||||
swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent);
|
||||
FILAMENT_CHECK_POSTCONDITION(swapChain) << "Unable to create swapchain";
|
||||
|
||||
VkSemaphoreCreateInfo const createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
||||
// No need to wait on this semaphore before drawing when in Headless mode.
|
||||
if (mHeadless) {
|
||||
// Set all sempahores to VK_NULL_HANDLE
|
||||
memset(mImageReady, 0, sizeof(mImageReady[0]) * IMAGE_READY_SEMAPHORE_COUNT);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
VkResult result =
|
||||
vkCreateSemaphore(mPlatform->getDevice(), &createInfo, nullptr, mImageReady + i);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Failed to create semaphore";
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -68,11 +52,6 @@ VulkanSwapChain::~VulkanSwapChain() {
|
||||
mCommands->wait();
|
||||
|
||||
mPlatform->destroy(swapChain);
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
if (mImageReady[i] != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(mPlatform->getDevice(), mImageReady[i], VKALLOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanSwapChain::update() {
|
||||
@@ -95,7 +74,7 @@ void VulkanSwapChain::update() {
|
||||
}
|
||||
|
||||
void VulkanSwapChain::present() {
|
||||
if (!mHeadless) {
|
||||
if (!mHeadless && mTransitionSwapChainImageLayoutForPresent) {
|
||||
VkCommandBuffer const cmdbuf = mCommands->get().buffer();
|
||||
VkImageSubresourceRange const subresources{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
@@ -106,10 +85,15 @@ void VulkanSwapChain::present() {
|
||||
};
|
||||
mColors[mCurrentSwapIndex]->transitionLayout(cmdbuf, subresources, VulkanLayout::PRESENT);
|
||||
}
|
||||
mCommands->flush();
|
||||
|
||||
// We only present if it is not headless. No-op for headless (but note that we still need the
|
||||
// flush() in the above line).
|
||||
mCommands->flush();
|
||||
|
||||
// call the image ready wait function
|
||||
if (mExplicitImageReadyWait != nullptr) {
|
||||
mExplicitImageReadyWait(swapChain);
|
||||
}
|
||||
|
||||
// We only present if it is not headless. No-op for headless.
|
||||
if (!mHeadless) {
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
@@ -139,13 +123,14 @@ void VulkanSwapChain::acquire(bool& resized) {
|
||||
update();
|
||||
}
|
||||
|
||||
mCurrentImageReadyIndex = (mCurrentImageReadyIndex + 1) % IMAGE_READY_SEMAPHORE_COUNT;
|
||||
const VkSemaphore imageReady = mImageReady[mCurrentImageReadyIndex];
|
||||
VkResult const result = mPlatform->acquire(swapChain, imageReady, &mCurrentSwapIndex);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||
<< "Cannot acquire in swapchain.";
|
||||
if (imageReady != VK_NULL_HANDLE) {
|
||||
mCommands->injectDependency(imageReady);
|
||||
VulkanPlatform::ImageSyncData imageSyncData;
|
||||
VkResult const result = mPlatform->acquire(swapChain, &imageSyncData);
|
||||
mCurrentSwapIndex = imageSyncData.imageIndex;
|
||||
mExplicitImageReadyWait = imageSyncData.explicitImageReadyWait;
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||
<< "Cannot acquire in swapchain.";
|
||||
if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) {
|
||||
mCommands->injectDependency(imageSyncData.imageReadySemaphore);
|
||||
}
|
||||
mAcquired = true;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,10 @@ struct VulkanSwapChain : public HwSwapChain, VulkanResource {
|
||||
void acquire(bool& reized);
|
||||
|
||||
inline VulkanTexture* getCurrentColor() const noexcept {
|
||||
return mColors[mCurrentSwapIndex].get();
|
||||
uint32_t const imageIndex = mCurrentSwapIndex;
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
imageIndex != VulkanPlatform::ImageSyncData::INVALID_IMAGE_INDEX);
|
||||
return mColors[imageIndex].get();
|
||||
}
|
||||
|
||||
inline VulkanTexture* getDepth() const noexcept {
|
||||
@@ -80,15 +83,15 @@ private:
|
||||
VulkanStagePool& mStagePool;
|
||||
bool const mHeadless;
|
||||
bool const mFlushAndWaitOnResize;
|
||||
bool const mTransitionSwapChainImageLayoutForPresent;
|
||||
|
||||
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
|
||||
// transitions, which are useful here.
|
||||
utils::FixedCapacityVector<std::unique_ptr<VulkanTexture>> mColors;
|
||||
std::unique_ptr<VulkanTexture> mDepth;
|
||||
VkExtent2D mExtent;
|
||||
VkSemaphore mImageReady[IMAGE_READY_SEMAPHORE_COUNT];
|
||||
uint32_t mCurrentImageReadyIndex;
|
||||
uint32_t mCurrentSwapIndex;
|
||||
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
|
||||
bool mAcquired;
|
||||
bool mIsFirstRenderPass;
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, mVkFormat, &props);
|
||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||
utils::slog.w << "Texture usage is SAMPLEABLE but format " << mVkFormat << " is not "
|
||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mVkFormat << " is not "
|
||||
"sampleable with optimal tiling." << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
@@ -163,7 +163,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
|
||||
VkResult error = vkCreateImage(mDevice, &imageInfo, VKALLOC, &mTextureImage);
|
||||
if (error || FVK_ENABLED(FVK_DEBUG_TEXTURE)) {
|
||||
utils::slog.d << "vkCreateImage: "
|
||||
FVK_LOGD << "vkCreateImage: "
|
||||
<< "image = " << mTextureImage << ", "
|
||||
<< "result = " << error << ", "
|
||||
<< "handle = " << utils::io::hex << mTextureImage << utils::io::dec << ", "
|
||||
@@ -450,7 +450,7 @@ void VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, const VkImageSubres
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||
utils::slog.d << "transition texture=" << mTextureImage
|
||||
FVK_LOGD << "transition texture=" << mTextureImage
|
||||
<< " (" << range.baseArrayLayer
|
||||
<< "," << range.baseMipLevel << ")"
|
||||
<< " count=(" << range.layerCount
|
||||
@@ -539,7 +539,7 @@ void VulkanTexture::print() const {
|
||||
layer < (mPrimaryViewRange.baseArrayLayer + mPrimaryViewRange.layerCount) &&
|
||||
level >= mPrimaryViewRange.baseMipLevel &&
|
||||
level < (mPrimaryViewRange.baseMipLevel + mPrimaryViewRange.levelCount);
|
||||
utils::slog.d << "[" << mTextureImage << "]: (" << layer << "," << level
|
||||
FVK_LOGD << "[" << mTextureImage << "]: (" << layer << "," << level
|
||||
<< ")=" << getLayout(layer, level)
|
||||
<< " primary=" << primary
|
||||
<< utils::io::endl;
|
||||
@@ -548,7 +548,7 @@ void VulkanTexture::print() const {
|
||||
|
||||
for (auto view: mCachedImageViews) {
|
||||
auto& range = view.first.range;
|
||||
utils::slog.d << "[" << mTextureImage << ", imageView=" << view.second << "]=>"
|
||||
FVK_LOGD << "[" << mTextureImage << ", imageView=" << view.second << "]=>"
|
||||
<< " (" << range.baseArrayLayer << "," << range.baseMipLevel << ")"
|
||||
<< " count=(" << range.layerCount << "," << range.levelCount << ")"
|
||||
<< " aspect=" << range.aspectMask << " viewType=" << view.first.type
|
||||
|
||||
@@ -95,7 +95,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
.pNext = &driverProperties,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
|
||||
utils::slog.i << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||
<< driverProperties.driverInfo << utils::io::endl;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
const FixedCapacityVector<VkPhysicalDevice> physicalDevices
|
||||
= filament::backend::enumerate(vkEnumeratePhysicalDevices, instance);
|
||||
|
||||
utils::slog.i << "Selected physical device '" << deviceProperties.deviceName << "' from "
|
||||
FVK_LOGI << "Selected physical device '" << deviceProperties.deviceName << "' from "
|
||||
<< physicalDevices.size() << " physical devices. "
|
||||
<< "(vendor " << utils::io::hex << vendorID << ", "
|
||||
<< "device " << deviceID << ", "
|
||||
@@ -142,15 +142,15 @@ void printDepthFormats(VkPhysicalDevice device) {
|
||||
// Note that Vulkan is more constrained than OpenGL ES 3.1 in this area.
|
||||
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
utils::slog.i << "Sampleable depth formats: ";
|
||||
FVK_LOGI << "Sampleable depth formats: ";
|
||||
for (VkFormat format : ALL_VK_FORMATS) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||
if ((props.optimalTilingFeatures & required) == required) {
|
||||
utils::slog.i << format << " ";
|
||||
FVK_LOGI << format << " ";
|
||||
}
|
||||
}
|
||||
utils::slog.i << utils::io::endl;
|
||||
FVK_LOGI << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -176,6 +176,12 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts =
|
||||
static_cast<char const*>(nullptr) /* pLayerName */);
|
||||
for (auto const& extProps: availableExts) {
|
||||
utils::CString name { extProps.extensionName };
|
||||
|
||||
// To workaround an Adreno bug where the extension name could be of 0 length.
|
||||
if (name.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setContains(TARGET_EXTS, name) || setContains(externallyRequiredExts, name)) {
|
||||
exts.insert(name);
|
||||
}
|
||||
@@ -192,6 +198,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE3_EXTENSION_NAME,
|
||||
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
||||
};
|
||||
ExtensionSet exts;
|
||||
// Identify supported physical device extensions
|
||||
@@ -200,6 +207,12 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
static_cast<const char*>(nullptr) /* pLayerName */);
|
||||
for (auto const& extension: extensions) {
|
||||
utils::CString name { extension.extensionName };
|
||||
|
||||
// To workaround an Adreno bug where the extension name could be of 0 length.
|
||||
if (name.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setContains(TARGET_EXTS, name)) {
|
||||
exts.insert(name);
|
||||
}
|
||||
@@ -229,11 +242,11 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data();
|
||||
} else {
|
||||
#if defined(__ANDROID__)
|
||||
utils::slog.d << "Validation layers are not available; did you set jniLibs in your "
|
||||
<< "gradle file?" << utils::io::endl;
|
||||
FVK_LOGD << "Validation layers are not available; did you set jniLibs in your "
|
||||
<< "gradle file?" << utils::io::endl;
|
||||
#else
|
||||
utils::slog.d << "Validation layer not available; did you install the Vulkan SDK?\n"
|
||||
<< "Please ensure that VK_LAYER_PATH is set correctly." << utils::io::endl;
|
||||
FVK_LOGD << "Validation layer not available; did you install the Vulkan SDK?\n"
|
||||
<< "Please ensure that VK_LAYER_PATH is set correctly." << utils::io::endl;
|
||||
#endif // __ANDROID__
|
||||
|
||||
}
|
||||
@@ -322,6 +335,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
||||
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
||||
|
||||
void* pNext = nullptr;
|
||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
@@ -329,9 +343,24 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
.mutableComparisonSamplers = VK_TRUE,
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||
deviceCreateInfo.pNext = &portability;
|
||||
portability.pNext = pNext;
|
||||
pNext = &portability;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.multiview = VK_TRUE,
|
||||
.multiviewGeometryShader = VK_FALSE,
|
||||
.multiviewTessellationShader = VK_FALSE
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
|
||||
multiview.pNext = pNext;
|
||||
pNext = &multiview;
|
||||
}
|
||||
|
||||
deviceCreateInfo.pNext = pNext;
|
||||
|
||||
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateDevice error=" << result << ".";
|
||||
|
||||
@@ -406,8 +435,8 @@ inline int deviceTypeOrder(VkPhysicalDeviceType deviceType) {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
||||
return 1;
|
||||
default:
|
||||
utils::slog.w << "deviceTypeOrder: Unexpected deviceType: " << deviceType
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "deviceTypeOrder: Unexpected deviceType: " << deviceType
|
||||
<< utils::io::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -689,6 +718,10 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
= pruneExtensions(mImpl->mPhysicalDevice, instExts, deviceExts);
|
||||
instExts = prunedInstExts;
|
||||
deviceExts = prunedDeviceExts;
|
||||
|
||||
if (driverConfig.stereoscopicType != StereoscopicType::MULTIVIEW) {
|
||||
deviceExts.erase(VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
mImpl->mDevice
|
||||
@@ -704,6 +737,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
// Store the extension support in the context
|
||||
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
|
||||
#ifdef NDEBUG
|
||||
// If we are in release build, we should not have turned on debug extensions
|
||||
@@ -738,8 +772,8 @@ VulkanPlatform::SwapChainBundle VulkanPlatform::getSwapChainBundle(SwapChainPtr
|
||||
SWAPCHAIN_RET_FUNC(getSwapChainBundle, handle, )
|
||||
}
|
||||
|
||||
VkResult VulkanPlatform::acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index) {
|
||||
SWAPCHAIN_RET_FUNC(acquire, handle, clientSignal, index)
|
||||
VkResult VulkanPlatform::acquire(SwapChainPtr handle, ImageSyncData* outImageSyncData) {
|
||||
SWAPCHAIN_RET_FUNC(acquire, handle, outImageSyncData)
|
||||
}
|
||||
|
||||
VkResult VulkanPlatform::present(SwapChainPtr handle, uint32_t index,
|
||||
|
||||
@@ -133,6 +133,7 @@ VulkanPlatformSurfaceSwapChain::VulkanPlatformSurfaceSwapChain(VulkanContext con
|
||||
VulkanPlatformSurfaceSwapChain::~VulkanPlatformSurfaceSwapChain() {
|
||||
vkDestroySwapchainKHR(mDevice, mSwapchain, VKALLOC);
|
||||
vkDestroySurfaceKHR(mInstance, mSurface, VKALLOC);
|
||||
destroy();
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
@@ -153,7 +154,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
// the number of images, though there may be limits related to the total amount of memory used
|
||||
// by presentable images."
|
||||
if (maxImageCount != 0 && desiredImageCount > maxImageCount) {
|
||||
utils::slog.e << "Swap chain does not support " << desiredImageCount << " images."
|
||||
FVK_LOGE << "Swap chain does not support " << desiredImageCount << " images."
|
||||
<< utils::io::endl;
|
||||
desiredImageCount = caps.minImageCount;
|
||||
}
|
||||
@@ -246,7 +247,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil);
|
||||
mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, mSwapChainBundle.depthFormat);
|
||||
|
||||
slog.i << "vkCreateSwapchain"
|
||||
FVK_LOGI << "vkCreateSwapchain"
|
||||
<< ": " << mSwapChainBundle.extent.width << "x" << mSwapChainBundle.extent.height << ", "
|
||||
<< surfaceFormat.format << ", " << surfaceFormat.colorSpace << ", "
|
||||
<< "swapchain-size=" << mSwapChainBundle.colors.size() << ", "
|
||||
@@ -254,19 +255,29 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
<< "depth=" << mSwapChainBundle.depthFormat
|
||||
<< io::endl;
|
||||
|
||||
VkSemaphoreCreateInfo const semaphoreCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
VkResult result = vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr,
|
||||
mImageReady + i);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Failed to create semaphore";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformSurfaceSwapChain::acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
// This immediately retrieves the index of the next available presentable image, and
|
||||
// asynchronously requests the GPU to trigger the "imageAvailable" semaphore.
|
||||
VkResult result = vkAcquireNextImageKHR(mDevice, mSwapchain, UINT64_MAX, clientSignal,
|
||||
VK_NULL_HANDLE, index);
|
||||
VkResult VulkanPlatformSurfaceSwapChain::acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
mCurrentImageReadyIndex = (mCurrentImageReadyIndex + 1) % IMAGE_READY_SEMAPHORE_COUNT;
|
||||
outImageSyncData->imageReadySemaphore = mImageReady[mCurrentImageReadyIndex];
|
||||
VkResult result = vkAcquireNextImageKHR(mDevice, mSwapchain, UINT64_MAX,
|
||||
outImageSyncData->imageReadySemaphore, VK_NULL_HANDLE, &outImageSyncData->imageIndex);
|
||||
|
||||
// Users should be notified of a suboptimal surface, but it should not cause a cascade of
|
||||
// log messages or a loop of re-creations.
|
||||
if (result == VK_SUBOPTIMAL_KHR && !mSuboptimal) {
|
||||
slog.w << "Vulkan Driver: Suboptimal swap chain." << io::endl;
|
||||
FVK_LOGW << "Vulkan Driver: Suboptimal swap chain." << io::endl;
|
||||
mSuboptimal = true;
|
||||
}
|
||||
return result;
|
||||
@@ -288,7 +299,7 @@ VkResult VulkanPlatformSurfaceSwapChain::present(uint32_t index, VkSemaphore fin
|
||||
// On Android Q and above, a suboptimal surface is always reported after screen rotation:
|
||||
// https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html
|
||||
if (result == VK_SUBOPTIMAL_KHR && !mSuboptimal) {
|
||||
utils::slog.w << "Vulkan Driver: Suboptimal swap chain." << utils::io::endl;
|
||||
FVK_LOGW << "Vulkan Driver: Suboptimal swap chain." << utils::io::endl;
|
||||
mSuboptimal = true;
|
||||
}
|
||||
return result;
|
||||
@@ -312,6 +323,17 @@ VkResult VulkanPlatformSurfaceSwapChain::recreate() {
|
||||
return create();
|
||||
}
|
||||
|
||||
void VulkanPlatformSurfaceSwapChain::destroy() {
|
||||
VulkanPlatformSwapChainImpl::destroy();
|
||||
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
if (mImageReady[i] != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(mDevice, mImageReady[i], VKALLOC);
|
||||
mImageReady[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPlatformHeadlessSwapChain::VulkanPlatformHeadlessSwapChain(VulkanContext const& context,
|
||||
VkDevice device, VkQueue queue, VkExtent2D extent, uint64_t flags)
|
||||
: VulkanPlatformSwapChainImpl(context, device, queue),
|
||||
@@ -343,8 +365,8 @@ VkResult VulkanPlatformHeadlessSwapChain::present(uint32_t index, VkSemaphore fi
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformHeadlessSwapChain::acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
*index = mCurrentIndex;
|
||||
VkResult VulkanPlatformHeadlessSwapChain::acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
outImageSyncData->imageIndex = mCurrentIndex;
|
||||
mCurrentIndex = (mCurrentIndex + 1) % HEADLESS_SWAPCHAIN_SIZE;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ struct VulkanPlatformSwapChainImpl : public Platform::SwapChain {
|
||||
~VulkanPlatformSwapChainImpl();
|
||||
|
||||
// Non-virtual override-able method
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
PANIC_PRECONDITION("Should not be called");
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ struct VulkanPlatformSurfaceSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
~VulkanPlatformSurfaceSwapChain();
|
||||
|
||||
// Non-virtual override
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index);
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData);
|
||||
|
||||
// Non-virtual override
|
||||
VkResult present(uint32_t index, VkSemaphore finished);
|
||||
@@ -97,7 +97,13 @@ struct VulkanPlatformSurfaceSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
// Non-virtual override-able method
|
||||
bool hasResized();
|
||||
|
||||
protected:
|
||||
// Non-virtual override-able method
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
static constexpr int IMAGE_READY_SEMAPHORE_COUNT = FVK_MAX_COMMAND_BUFFERS;
|
||||
|
||||
VkResult create();
|
||||
|
||||
VkInstance mInstance;
|
||||
@@ -106,6 +112,8 @@ private:
|
||||
VkSurfaceKHR mSurface;
|
||||
VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
|
||||
VkExtent2D const mFallbackExtent;
|
||||
VkSemaphore mImageReady[IMAGE_READY_SEMAPHORE_COUNT];
|
||||
uint32_t mCurrentImageReadyIndex;
|
||||
|
||||
bool mUsesRGB = false;
|
||||
bool mHasStencil = false;
|
||||
@@ -121,7 +129,7 @@ struct VulkanPlatformHeadlessSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
~VulkanPlatformHeadlessSwapChain();
|
||||
|
||||
// Non-virtual override
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index);
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData);
|
||||
|
||||
// Non-virtual override
|
||||
VkResult present(uint32_t index, VkSemaphore finished);
|
||||
|
||||
@@ -930,6 +930,14 @@ public:
|
||||
*/
|
||||
void pumpMessageQueues();
|
||||
|
||||
/**
|
||||
* Switch the command queue to unprotected mode. Protected mode can be activated via
|
||||
* Renderer::beginFrame() using a protected SwapChain.
|
||||
* @see Renderer
|
||||
* @see SwapChain
|
||||
*/
|
||||
void unprotected() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the default Material.
|
||||
*
|
||||
|
||||
@@ -140,6 +140,7 @@ public:
|
||||
* @param values Array of values to set to the named parameter array.
|
||||
* @param count Size of the array to set.
|
||||
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
|
||||
* @see Material::hasParameter
|
||||
*/
|
||||
template<typename T, typename = is_supported_parameter_t<T>>
|
||||
void setParameter(const char* UTILS_NONNULL name, size_t nameLength,
|
||||
@@ -234,6 +235,32 @@ public:
|
||||
setParameter(name, strlen(name), type, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a parameter by name.
|
||||
*
|
||||
* Note: Only supports non-texture parameters such as numeric and math types.
|
||||
*
|
||||
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
|
||||
* @param nameLength Length in `char` of the name parameter.
|
||||
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
|
||||
*
|
||||
* @see Material::hasParameter
|
||||
*/
|
||||
template<typename T>
|
||||
T getParameter(const char* UTILS_NONNULL name, size_t nameLength) const;
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_parameter_t<T>>
|
||||
inline T getParameter(StringLiteral name) const {
|
||||
return getParameter<T>(name.data, name.size);
|
||||
}
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_parameter_t<T>>
|
||||
inline T getParameter(const char* UTILS_NONNULL name) const {
|
||||
return getParameter<T>(name, strlen(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
|
||||
@@ -329,6 +329,10 @@ void Engine::pumpMessageQueues() {
|
||||
downcast(this)->pumpMessageQueues();
|
||||
}
|
||||
|
||||
void Engine::unprotected() noexcept {
|
||||
downcast(this)->unprotected();
|
||||
}
|
||||
|
||||
void Engine::setAutomaticInstancingEnabled(bool enable) noexcept {
|
||||
downcast(this)->setAutomaticInstancingEnabled(enable);
|
||||
}
|
||||
|
||||
@@ -183,6 +183,35 @@ template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char*
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
T FMaterialInstance::getParameterImpl(std::string_view name) const {
|
||||
ssize_t offset = mMaterial->getUniformInterfaceBlock().getFieldOffset(name, 0);
|
||||
assert_invariant(offset>=0);
|
||||
return downcast(this)->getUniformBuffer().getUniform<T>(offset);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T MaterialInstance::getParameter(const char* name, size_t nameLength) const {
|
||||
return downcast(this)->getParameterImpl<T>({ name, nameLength });
|
||||
}
|
||||
|
||||
// explicit template instantiation of our supported types
|
||||
template UTILS_PUBLIC float MaterialInstance::getParameter<float> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int32_t MaterialInstance::getParameter<int32_t> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint32_t MaterialInstance::getParameter<uint32_t>(const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int2 MaterialInstance::getParameter<int2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int3 MaterialInstance::getParameter<int3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int4 MaterialInstance::getParameter<int4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint2 MaterialInstance::getParameter<uint2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint3 MaterialInstance::getParameter<uint3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint4 MaterialInstance::getParameter<uint4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float2 MaterialInstance::getParameter<float2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float3 MaterialInstance::getParameter<float3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float4 MaterialInstance::getParameter<float4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC mat3f MaterialInstance::getParameter<mat3f> (const char* name, size_t nameLength) const;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Material const* MaterialInstance::getMaterial() const noexcept {
|
||||
return downcast(this)->getMaterial();
|
||||
}
|
||||
|
||||
@@ -476,6 +476,8 @@ void FEngine::shutdown() {
|
||||
|
||||
destroy(mDefaultMaterial);
|
||||
|
||||
destroy(mUnprotectedDummySwapchain);
|
||||
|
||||
/*
|
||||
* clean-up after the user -- we call terminate on each "leaked" object and clear each list.
|
||||
*
|
||||
@@ -1253,6 +1255,13 @@ void FEngine::resetBackendState() noexcept {
|
||||
}
|
||||
#endif
|
||||
|
||||
void FEngine::unprotected() noexcept {
|
||||
if (UTILS_UNLIKELY(!mUnprotectedDummySwapchain)) {
|
||||
mUnprotectedDummySwapchain = createSwapChain(1, 1, 0);
|
||||
}
|
||||
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Engine::Builder::Builder() noexcept = default;
|
||||
|
||||
@@ -406,6 +406,8 @@ public:
|
||||
getDriver().purge();
|
||||
}
|
||||
|
||||
void unprotected() noexcept;
|
||||
|
||||
void setAutomaticInstancingEnabled(bool enable) noexcept {
|
||||
// instancing is not allowed at feature level 0
|
||||
if (hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1)) {
|
||||
@@ -539,6 +541,7 @@ private:
|
||||
|
||||
mutable FMaterial const* mDefaultMaterial = nullptr;
|
||||
mutable FMaterial const* mSkyboxMaterial = nullptr;
|
||||
mutable FSwapChain* mUnprotectedDummySwapchain = nullptr;
|
||||
|
||||
mutable FTexture* mDefaultIblTexture = nullptr;
|
||||
mutable FIndirectLight* mDefaultIbl = nullptr;
|
||||
@@ -595,6 +598,7 @@ public:
|
||||
// capture to file. At the moment, only supported by the Metal backend.
|
||||
bool doFrameCapture = false;
|
||||
bool disable_buffer_padding = false;
|
||||
bool disable_subpasses = false;
|
||||
} renderer;
|
||||
struct {
|
||||
bool debug_froxel_visualization = false;
|
||||
|
||||
@@ -661,7 +661,7 @@ bool FMaterial::hasPendingEdits() noexcept {
|
||||
|
||||
void FMaterial::latchPendingEdits() noexcept {
|
||||
std::lock_guard const lock(mPendingEditsLock);
|
||||
std::swap(mPendingEdits, mMaterialParser);
|
||||
mMaterialParser.reset(mPendingEdits.release());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -231,6 +231,9 @@ private:
|
||||
void setParameterImpl(std::string_view name,
|
||||
FTexture const* texture, TextureSampler const& sampler);
|
||||
|
||||
template<typename T>
|
||||
T getParameterImpl(std::string_view name) const;
|
||||
|
||||
// initialize the default instance
|
||||
FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept;
|
||||
|
||||
|
||||
@@ -95,6 +95,8 @@ FRenderer::FRenderer(FEngine& engine) :
|
||||
&engine.debug.renderer.doFrameCapture);
|
||||
debugRegistry.registerProperty("d.renderer.disable_buffer_padding",
|
||||
&engine.debug.renderer.disable_buffer_padding);
|
||||
debugRegistry.registerProperty("d.renderer.disable_subpasses",
|
||||
&engine.debug.renderer.disable_subpasses);
|
||||
debugRegistry.registerProperty("d.shadowmap.display_shadow_texture",
|
||||
&engine.debug.shadowmap.display_shadow_texture);
|
||||
debugRegistry.registerProperty("d.shadowmap.display_shadow_texture_scale",
|
||||
@@ -596,12 +598,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
hasColorGrading &&
|
||||
msaaSampleCount <= 1 &&
|
||||
!bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled &&
|
||||
driver.isFrameBufferFetchSupported(),
|
||||
driver.isFrameBufferFetchSupported() &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
.customResolve =
|
||||
msaaOptions.customResolve &&
|
||||
msaaSampleCount > 1 &&
|
||||
hasColorGrading &&
|
||||
driver.isFrameBufferFetchMultiSampleSupported(),
|
||||
driver.isFrameBufferFetchMultiSampleSupported() &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
.translucent = needsAlphaChannel,
|
||||
.fxaa = hasFXAA,
|
||||
.dithering = hasDithering,
|
||||
|
||||
@@ -114,6 +114,7 @@ void FSkinningBuffer::setBones(FEngine& engine,
|
||||
setBones(engine, mHandle, transforms, count, offset);
|
||||
}
|
||||
|
||||
UTILS_UNUSED
|
||||
static uint32_t packHalf2x16(half2 v) noexcept {
|
||||
uint32_t lo = getBits(v[0]);
|
||||
uint32_t hi = getBits(v[1]);
|
||||
@@ -144,13 +145,8 @@ PerRenderableBoneUib::BoneData FSkinningBuffer::makeBone(mat4f transform) noexce
|
||||
transform[1],
|
||||
transform[2]
|
||||
},
|
||||
.cof = {
|
||||
packHalf2x16({ cofactors[0].x, cofactors[0].y }),
|
||||
packHalf2x16({ cofactors[0].z, cofactors[1].x }),
|
||||
packHalf2x16({ cofactors[1].y, cofactors[1].z }),
|
||||
packHalf2x16({ cofactors[2].x, cofactors[2].y })
|
||||
// cofactor[2][2] is not stored because we don't have space for it
|
||||
}
|
||||
.cof0 = cofactors[0],
|
||||
.cof1x = cofactors[1].x
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.52.3"
|
||||
spec.version = "1.53.1"
|
||||
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.52.3/filament-v1.52.3-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.53.1/filament-v1.53.1-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 52;
|
||||
static constexpr size_t MATERIAL_VERSION = 53;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -327,8 +327,9 @@ struct PerRenderableBoneUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
struct alignas(16) BoneData {
|
||||
// bone transform, last row assumed [0,0,0,1]
|
||||
math::float4 transform[3];
|
||||
// 8 first cofactor matrix of transform's upper left
|
||||
math::uint4 cof;
|
||||
// 4 first cofactor matrix of transform's upper left
|
||||
math::float3 cof0;
|
||||
float cof1x;
|
||||
};
|
||||
BoneData bones[CONFIG_MAX_BONE_COUNT];
|
||||
};
|
||||
|
||||
@@ -207,7 +207,17 @@ std::vector<BufferSlot> computeGeometries(cgltf_primitive const* prim, uint8_t c
|
||||
|
||||
size_t const requiredSize = byteCount * vertexCount;
|
||||
auto gendata = (uint8_t*) malloc(requiredSize);
|
||||
memset(gendata, 0xff, requiredSize);
|
||||
|
||||
if (vattr == filament::VertexAttribute::COLOR) {
|
||||
// Assume white as the default if colors need to be generated.
|
||||
float4* dataf = (float4*) gendata;
|
||||
for (size_t i = 0; i < vertexCount; ++i) {
|
||||
dataf[i] = float4(1.0, 1.0, 1.0, 1.0f);
|
||||
}
|
||||
} else {
|
||||
memset(gendata, 0xff, requiredSize);
|
||||
}
|
||||
|
||||
vslots.push_back({
|
||||
.slot = slot,
|
||||
.sizeInBytes = requiredSize,
|
||||
|
||||
@@ -55,9 +55,15 @@ public:
|
||||
int reportActualWorkDuration(int64_t actualDurationNanos) noexcept;
|
||||
};
|
||||
|
||||
// caveat: This must be called on a Java thread
|
||||
PerformanceHintManager() noexcept;
|
||||
~PerformanceHintManager() noexcept;
|
||||
|
||||
// Whether PerformanceHintManager APIs are supported (which doesn't mean PerformanceHintManager
|
||||
// itself is, use isValid()).
|
||||
static bool isSupported() noexcept;
|
||||
|
||||
// Whether PerformanceHintManager can be used.
|
||||
bool isValid() const;
|
||||
|
||||
int64_t getPreferredUpdateRateNanos() const noexcept;
|
||||
|
||||
@@ -47,6 +47,13 @@ PerformanceHintManager::PerformanceHintManager() noexcept {
|
||||
|
||||
PerformanceHintManager::~PerformanceHintManager() noexcept = default;
|
||||
|
||||
bool PerformanceHintManager::isSupported() noexcept {
|
||||
if (__builtin_available(android __ANDROID_API_T__, *)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PerformanceHintManager::isValid() const {
|
||||
return mImpl->mManager != nullptr;
|
||||
}
|
||||
|
||||
@@ -856,6 +856,8 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
ImGui::Checkbox("Disable buffer padding",
|
||||
debug.getPropertyAddress<bool>("d.renderer.disable_buffer_padding"));
|
||||
ImGui::Checkbox("Disable sub-passes",
|
||||
debug.getPropertyAddress<bool>("d.renderer.disable_subpasses"));
|
||||
ImGui::Checkbox("Camera at origin",
|
||||
debug.getPropertyAddress<bool>("d.view.camera_at_origin"));
|
||||
ImGui::Checkbox("Far Origin", &app.originIsFarAway);
|
||||
|
||||
+63
-6
@@ -29,6 +29,10 @@
|
||||
#include <filamentapp/Config.h>
|
||||
#include <filamentapp/FilamentApp.h>
|
||||
|
||||
#include <getopt/getopt.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "generated/resources/resources.h"
|
||||
#include "generated/resources/monkey.h"
|
||||
|
||||
@@ -39,6 +43,7 @@ using namespace filament::math;
|
||||
using Backend = Engine::Backend;
|
||||
|
||||
struct App {
|
||||
Config config;
|
||||
utils::Entity light;
|
||||
Material* material;
|
||||
MaterialInstance* materialInstance;
|
||||
@@ -48,13 +53,65 @@ struct App {
|
||||
|
||||
static const char* IBL_FOLDER = "assets/ibl/lightroom_14b";
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Config config;
|
||||
config.title = "hellopbr";
|
||||
config.iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER;
|
||||
static void printUsage(char* name) {
|
||||
std::string exec_name(utils::Path(name).getName());
|
||||
std::string usage(
|
||||
"EXEC renders a simple PBR example\n"
|
||||
"Usage:\n"
|
||||
" EXEC [options]\n"
|
||||
"Options:\n"
|
||||
" --help, -h\n"
|
||||
" Prints this message\n\n"
|
||||
" --api, -a\n"
|
||||
" Specify the backend API: opengl, vulkan, or metal\n"
|
||||
);
|
||||
const std::string from("EXEC");
|
||||
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
|
||||
usage.replace(pos, from.length(), exec_name);
|
||||
}
|
||||
std::cout << usage;
|
||||
}
|
||||
|
||||
static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
static constexpr const char* OPTSTR = "ha:";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
|
||||
std::string arg(optarg ? optarg : "");
|
||||
switch (opt) {
|
||||
default:
|
||||
case 'h':
|
||||
printUsage(argv[0]);
|
||||
exit(0);
|
||||
case 'a':
|
||||
if (arg == "opengl") {
|
||||
app->config.backend = Engine::Backend::OPENGL;
|
||||
} else if (arg == "vulkan") {
|
||||
app->config.backend = Engine::Backend::VULKAN;
|
||||
} else if (arg == "metal") {
|
||||
app->config.backend = Engine::Backend::METAL;
|
||||
} else {
|
||||
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n";
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return optind;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
App app;
|
||||
auto setup = [config, &app](Engine* engine, View* view, Scene* scene) {
|
||||
app.config.title = "hellopbr";
|
||||
app.config.iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER;
|
||||
handleCommandLineArguments(argc, argv, &app);
|
||||
|
||||
auto setup = [config=app.config, &app](Engine* engine, View* view, Scene* scene) {
|
||||
auto& tcm = engine->getTransformManager();
|
||||
auto& rcm = engine->getRenderableManager();
|
||||
auto& em = utils::EntityManager::get();
|
||||
@@ -100,7 +157,7 @@ int main(int argc, char** argv) {
|
||||
tcm.setTransform(ti, app.transform * mat4f::rotation(now, float3{ 0, 1, 0 }));
|
||||
});
|
||||
|
||||
FilamentApp::get().run(config, setup, cleanup);
|
||||
FilamentApp::get().run(app.config, setup, cleanup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ struct ShadowData {
|
||||
#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
|
||||
struct BoneData {
|
||||
highp mat3x4 transform; // bone transform is mat4x3 stored in row-major (last row [0,0,0,1])
|
||||
highp uvec4 cof; // 8 first cofactor matrix of transform's upper left
|
||||
highp float3 cof0; // 3 first cofactor matrix of transform's upper left
|
||||
highp float cof1x; // 4th cofactor
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
+21
-14
@@ -34,25 +34,32 @@ int getVertexIndex() {
|
||||
|
||||
#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
|
||||
#define MAX_SKINNING_BUFFER_WIDTH 2048u
|
||||
vec3 mulBoneNormal(vec3 n, uint i) {
|
||||
vec3 mulBoneNormal(vec3 n, uint j) {
|
||||
|
||||
highp mat3 cof;
|
||||
|
||||
// the first 8 elements of the cofactor matrix are stored as fp16
|
||||
highp vec2 x0y0 = unpackHalf2x16(bonesUniforms.bones[i].cof[0]);
|
||||
highp vec2 z0x1 = unpackHalf2x16(bonesUniforms.bones[i].cof[1]);
|
||||
highp vec2 y1z1 = unpackHalf2x16(bonesUniforms.bones[i].cof[2]);
|
||||
highp vec2 x2y2 = unpackHalf2x16(bonesUniforms.bones[i].cof[3]);
|
||||
|
||||
// the last element must be computed by hand
|
||||
highp float a = bonesUniforms.bones[i].transform[0][0];
|
||||
highp float b = bonesUniforms.bones[i].transform[0][1];
|
||||
highp float d = bonesUniforms.bones[i].transform[1][0];
|
||||
highp float e = bonesUniforms.bones[i].transform[1][1];
|
||||
highp float a = bonesUniforms.bones[j].transform[0][0];
|
||||
highp float b = bonesUniforms.bones[j].transform[0][1];
|
||||
highp float c = bonesUniforms.bones[j].transform[0][2];
|
||||
highp float d = bonesUniforms.bones[j].transform[1][0];
|
||||
highp float e = bonesUniforms.bones[j].transform[1][1];
|
||||
highp float f = bonesUniforms.bones[j].transform[1][2];
|
||||
highp float g = bonesUniforms.bones[j].transform[2][0];
|
||||
highp float h = bonesUniforms.bones[j].transform[2][1];
|
||||
highp float i = bonesUniforms.bones[j].transform[2][2];
|
||||
|
||||
cof[0].xyz = vec3(x0y0, z0x1.x);
|
||||
cof[1].xyz = vec3(z0x1.y, y1z1);
|
||||
cof[2].xyz = vec3(x2y2, a * e - b * d);
|
||||
cof[0] = bonesUniforms.bones[j].cof0;
|
||||
|
||||
cof[1].xyz = vec3(
|
||||
bonesUniforms.bones[j].cof1x,
|
||||
a * i - c * g,
|
||||
c * d - a * f);
|
||||
|
||||
cof[2].xyz = vec3(
|
||||
d * h - e * g,
|
||||
b * g - a * h,
|
||||
a * e - b * d);
|
||||
|
||||
return normalize(cof * n);
|
||||
}
|
||||
|
||||
@@ -388,6 +388,8 @@ class_<Engine>("Engine")
|
||||
return Engine::create();
|
||||
}, allow_raw_pointers())
|
||||
|
||||
.function("unprotected", &Engine::unprotected)
|
||||
|
||||
.function("enableAccurateTranslations", &Engine::enableAccurateTranslations)
|
||||
|
||||
.function("setAutomaticInstancingEnabled", &Engine::setAutomaticInstancingEnabled)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.52.3",
|
||||
"version": "1.53.1",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user