backend: Propagate backend thread exceptions to the main thread. (#9903)
* Filament Error Handling Remediation and noexcept Cleanup - Replaced assert_invariant with FILAMENT_CHECK_PRECONDITION in Renderer::beginFrame for caller bugs. - Removed noexcept from Camera::setCustomProjection to allow precondition checks to throw. - Removed noexcept from Texture and InstanceBuffer methods using precondition checks. - Documented silent clamping in View::setBloomOptions. - Clarified comment in FrameGraphResources regarding preconditions. - Refined MaterialInstance::commit to split texture loop into check and update passes, preventing partial state changes on precondition failure. * backend: Propagate backend thread exceptions to the main thread. Introduce a mechanism to catch exceptions thrown on the backend thread and rethrow them on the main thread. This prevents deadlocks and allows the application to handle fatal backend failures gracefully. - Consolidate synchronization primitives in DriverBase. - Add mHasUnrecoverableError flag to interrupt blocked fence waits. - Optimize waitForFence to avoid extra atomic reads in common paths. - Propagate FenceStatus::ERROR across all backends. - CommandBufferQueue now stores a std::exception_ptr when the backend fails. - The backend enters a "zombie" state on failure, skipping further command execution but allowing clean shutdown. - Public APIs in Renderer and Engine now check for stored exceptions and rethrow them, documented with @throws. - Guarded by __EXCEPTIONS to ensure no overhead when exceptions are disabled. - Add unit test for fence interruption and document new APIs. BUGS=[407545700] * feat: harden backend exceptions and add hasUnrecoverableFailure API - Update Renderer::beginFrame() and Renderer::shouldRenderFrame() to return false early if an unrecoverable backend exception has been delivered to the main thread. - Document the new return behavior for beginFrame() and shouldRenderFrame() in Renderer.h. - Add Engine::hasUnrecoverableFailure() to the public API to allow apps to check for fatal errors without relying on exceptions. - Implement hasUnrecoverableFailure() in FEngine by delegating to CommandBufferQueue. - Expose Engine::hasUnrecoverableFailure() to Java bindings (Engine.java and JNI). - Expose Engine::hasUnrecoverableFailure() to JavaScript bindings (jsbindings.cpp). * java: propagate C++ Panics & exceptions to JAVA
This commit is contained in:
@@ -75,6 +75,17 @@ void JniCallback::postToJavaAndDestroy(JniCallback* callback) {
|
||||
delete callback;
|
||||
}
|
||||
|
||||
void JniCallback::destroy(JniCallback* callback) {
|
||||
JNIEnv* env = filament::VirtualMachineEnv::get().getEnvironment();
|
||||
env->DeleteGlobalRef(callback->mHandler);
|
||||
env->DeleteGlobalRef(callback->mCallback);
|
||||
#ifdef __ANDROID__
|
||||
env->DeleteGlobalRef(callback->mCallbackUtils.handlerClass);
|
||||
#endif
|
||||
env->DeleteGlobalRef(callback->mCallbackUtils.executorClass);
|
||||
delete callback;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
JniBufferCallback* JniBufferCallback::make(filament::Engine*,
|
||||
|
||||
@@ -48,6 +48,9 @@ struct JniCallback : private filament::backend::CallbackHandler {
|
||||
// execute the callback on the java thread and destroy ourselves
|
||||
static void postToJavaAndDestroy(JniCallback* callback);
|
||||
|
||||
// destroy ourselves without executing the callback
|
||||
static void destroy(JniCallback* callback);
|
||||
|
||||
// CallbackHandler interface.
|
||||
void post(void* user, Callback callback) override;
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 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 "JniUtils.h"
|
||||
|
||||
namespace filament {
|
||||
namespace android {
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
|
||||
UTILS_NOINLINE void wrapJniHelper(JNIEnv* env, void (*invoker)(void*), void* userData) {
|
||||
try {
|
||||
invoker(userData);
|
||||
} catch (const utils::PreconditionPanic& e) {
|
||||
jclass exClass = env->FindClass("java/lang/IllegalArgumentException");
|
||||
env->ThrowNew(exClass, e.what());
|
||||
} catch (const utils::PostconditionPanic& e) {
|
||||
jclass exClass = env->FindClass("java/lang/RuntimeException");
|
||||
env->ThrowNew(exClass, e.what());
|
||||
} catch (const std::exception& e) {
|
||||
jclass exClass = env->FindClass("java/lang/RuntimeException");
|
||||
env->ThrowNew(exClass, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
UTILS_NOINLINE void wrapJniBackendHelper(JNIEnv* env, void (*invoker)(void*), void* userData) {
|
||||
try {
|
||||
invoker(userData);
|
||||
} catch (const std::exception& e) {
|
||||
jclass exClass = env->FindClass("java/lang/RuntimeException");
|
||||
env->ThrowNew(exClass, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace android
|
||||
} // namespace filament
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_ANDROID_COMMON_JNIUTILS_H
|
||||
#define TNT_ANDROID_COMMON_JNIUTILS_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace filament {
|
||||
namespace android {
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
|
||||
// Non-templated helpers implemented in JniUtils.cpp
|
||||
void wrapJniHelper(JNIEnv* env, void (*invoker)(void*), void* userData);
|
||||
void wrapJniBackendHelper(JNIEnv* env, void (*invoker)(void*), void* userData);
|
||||
|
||||
// For JNI methods that return a value
|
||||
template<typename R, typename F>
|
||||
R wrapJni(JNIEnv* env, F const& f) {
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
auto invoker = [](void* data) {
|
||||
auto& f_ref = *reinterpret_cast<const F*>(data);
|
||||
f_ref();
|
||||
};
|
||||
wrapJniHelper(env, invoker, (void*)&f);
|
||||
} else {
|
||||
struct Context {
|
||||
const F& f;
|
||||
R result;
|
||||
};
|
||||
Context ctx{ f, R{} };
|
||||
auto invoker = [](void* data) {
|
||||
auto& context = *reinterpret_cast<Context*>(data);
|
||||
context.result = context.f();
|
||||
};
|
||||
wrapJniHelper(env, invoker, &ctx);
|
||||
return ctx.result;
|
||||
}
|
||||
}
|
||||
|
||||
// Overload for JNI methods that return void
|
||||
template<typename F>
|
||||
inline void wrapJni(JNIEnv* env, F const& f) {
|
||||
wrapJni<void, F>(env, f);
|
||||
}
|
||||
|
||||
// For JNI methods that can return backend errors (mapped to java.lang.Error)
|
||||
template<typename R, typename F>
|
||||
R wrapJniBackend(JNIEnv* env, F const& f) {
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
auto invoker = [](void* data) {
|
||||
auto& f_ref = *reinterpret_cast<const F*>(data);
|
||||
f_ref();
|
||||
};
|
||||
wrapJniBackendHelper(env, invoker, (void*)&f);
|
||||
} else {
|
||||
struct Context {
|
||||
const F& f;
|
||||
R result;
|
||||
};
|
||||
Context ctx{ f, R{} };
|
||||
auto invoker = [](void* data) {
|
||||
auto& context = *reinterpret_cast<Context*>(data);
|
||||
context.result = context.f();
|
||||
};
|
||||
wrapJniBackendHelper(env, invoker, &ctx);
|
||||
return ctx.result;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void wrapJniBackend(JNIEnv* env, F const& f) {
|
||||
wrapJniBackend<void, F>(env, f);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// For JNI methods that return a value
|
||||
template<typename R, typename F>
|
||||
R wrapJni(JNIEnv* env, F const& f) {
|
||||
return f();
|
||||
}
|
||||
|
||||
// Overload for JNI methods that return void
|
||||
template<typename F>
|
||||
inline void wrapJni(JNIEnv* env, F const& f) {
|
||||
f();
|
||||
}
|
||||
|
||||
template<typename R, typename F>
|
||||
R wrapJniBackend(JNIEnv* env, F const& f) {
|
||||
return f();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void wrapJniBackend(JNIEnv* env, F const& f) {
|
||||
f();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace android
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_ANDROID_COMMON_JNIUTILS_H
|
||||
@@ -126,6 +126,7 @@ add_library(filament-jni SHARED
|
||||
# Common utils
|
||||
../common/CallbackUtils.cpp
|
||||
../common/NioUtils.cpp
|
||||
../common/JniUtils.cpp
|
||||
)
|
||||
|
||||
target_include_directories(filament-jni PRIVATE
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -26,6 +25,7 @@
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
@@ -63,7 +63,9 @@ Java_com_google_android_filament_BufferObject_nBuilderBuild(JNIEnv *env, jclass
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
BufferObject::Builder* builder = (BufferObject::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -81,20 +83,22 @@ Java_com_google_android_filament_BufferObject_nSetBuffer(JNIEnv *env, jclass typ
|
||||
BufferObject *bufferObject = (BufferObject *) nativeBufferObject;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
AutoBuffer nioBuffer(env, buffer, count);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
return filament::android::wrapJni<int>(env, [=]() {
|
||||
AutoBuffer nioBuffer(env, buffer, count);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto* callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
|
||||
auto* callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
|
||||
|
||||
BufferDescriptor desc(data, sizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
BufferDescriptor desc(data, sizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
bufferObject->setBuffer(*engine, std::move(desc), (uint32_t) destOffsetInBytes);
|
||||
bufferObject->setBuffer(*engine, std::move(desc), (uint32_t) destOffsetInBytes);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <filament/Camera.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
|
||||
#include <utils/Entity.h>
|
||||
@@ -24,21 +25,26 @@
|
||||
#include <math/mat4.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Camera_nSetProjection(JNIEnv*, jclass, jlong nativeCamera,
|
||||
Java_com_google_android_filament_Camera_nSetProjection(JNIEnv* env, jclass, jlong nativeCamera,
|
||||
jint projection, jdouble left, jdouble right, jdouble bottom, jdouble top, jdouble near,
|
||||
jdouble far) {
|
||||
Camera *camera = (Camera *) nativeCamera;
|
||||
camera->setProjection((Camera::Projection) projection, left, right, bottom, top, near, far);
|
||||
wrapJni(env, [=]() {
|
||||
camera->setProjection((Camera::Projection) projection, left, right, bottom, top, near, far);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Camera_nSetProjectionFov(JNIEnv*, jclass ,
|
||||
Java_com_google_android_filament_Camera_nSetProjectionFov(JNIEnv* env, jclass ,
|
||||
jlong nativeCamera, jdouble fovInDegrees, jdouble aspect, jdouble near, jdouble far,
|
||||
jint fov) {
|
||||
Camera *camera = (Camera *) nativeCamera;
|
||||
camera->setProjection(fovInDegrees, aspect, near, far, (Camera::Fov) fov);
|
||||
wrapJni(env, [=]() {
|
||||
camera->setProjection(fovInDegrees, aspect, near, far, (Camera::Fov) fov);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jdouble JNICALL
|
||||
@@ -49,10 +55,12 @@ Java_com_google_android_filament_Camera_nGetFieldOfViewInDegrees(JNIEnv*, jclass
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Camera_nSetLensProjection(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Camera_nSetLensProjection(JNIEnv* env, jclass,
|
||||
jlong nativeCamera, jdouble focalLength, jdouble aspect, jdouble near, jdouble far) {
|
||||
Camera *camera = (Camera *) nativeCamera;
|
||||
camera->setLensProjection(focalLength, aspect, near, far);
|
||||
wrapJni(env, [=]() {
|
||||
camera->setLensProjection(focalLength, aspect, near, far);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -62,10 +70,12 @@ Java_com_google_android_filament_Camera_nSetCustomProjection(JNIEnv *env, jclass
|
||||
Camera *camera = (Camera *) nativeCamera;
|
||||
jdouble *inProjection = env->GetDoubleArrayElements(inProjection_, NULL);
|
||||
jdouble *inProjectionForCulling = env->GetDoubleArrayElements(inProjectionForCulling_, NULL);
|
||||
camera->setCustomProjection(
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjection),
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjectionForCulling),
|
||||
near, far);
|
||||
wrapJni(env, [=]() {
|
||||
camera->setCustomProjection(
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjection),
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjectionForCulling),
|
||||
near, far);
|
||||
});
|
||||
env->ReleaseDoubleArrayElements(inProjection_, inProjection, JNI_ABORT);
|
||||
env->ReleaseDoubleArrayElements(inProjectionForCulling_, inProjectionForCulling, JNI_ABORT);
|
||||
}
|
||||
@@ -77,10 +87,12 @@ Java_com_google_android_filament_Camera_nSetCustomEyeProjection(JNIEnv *env, jcl
|
||||
Camera *camera = (Camera *) nativeCamera;
|
||||
jdouble *inProjection = env->GetDoubleArrayElements(inProjection_, NULL);
|
||||
jdouble *inProjectionForCulling = env->GetDoubleArrayElements(inProjectionForCulling_, NULL);
|
||||
camera->setCustomEyeProjection(
|
||||
reinterpret_cast<const filament::math::mat4 *>(inProjection), (size_t) count,
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjectionForCulling),
|
||||
near, far);
|
||||
wrapJni(env, [=]() {
|
||||
camera->setCustomEyeProjection(
|
||||
reinterpret_cast<const filament::math::mat4 *>(inProjection), (size_t) count,
|
||||
*reinterpret_cast<const filament::math::mat4 *>(inProjectionForCulling),
|
||||
near, far);
|
||||
});
|
||||
env->ReleaseDoubleArrayElements(inProjection_, inProjection, JNI_ABORT);
|
||||
env->ReleaseDoubleArrayElements(inProjectionForCulling_, inProjectionForCulling, JNI_ABORT);
|
||||
}
|
||||
@@ -154,7 +166,9 @@ Java_com_google_android_filament_Camera_nSetEyeModelMatrix(JNIEnv *env, jclass,
|
||||
jlong nativeCamera, jint eyeId, jdoubleArray model_) {
|
||||
Camera* camera = (Camera *) nativeCamera;
|
||||
jdouble *model = env->GetDoubleArrayElements(model_, NULL);
|
||||
camera->setEyeModelMatrix((uint8_t)eyeId, *reinterpret_cast<const filament::math::mat4*>(model));
|
||||
wrapJni(env, [=]() {
|
||||
camera->setEyeModelMatrix((uint8_t)eyeId, *reinterpret_cast<const filament::math::mat4 *>(model));
|
||||
});
|
||||
env->ReleaseDoubleArrayElements(model_, model, JNI_ABORT);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace math;
|
||||
@@ -37,10 +38,12 @@ Java_com_google_android_filament_ColorGrading_nDestroyBuilder(JNIEnv*, jclass, j
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_ColorGrading_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jlong nativeEngine) {
|
||||
Java_com_google_android_filament_ColorGrading_nBuilderBuild(JNIEnv* env, jclass, jlong nativeBuilder, jlong nativeEngine) {
|
||||
ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/MorphTargetBuffer.h>
|
||||
@@ -28,14 +30,18 @@
|
||||
#include <filament/View.h>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/JniUtils.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv*, jclass, jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Engine::destroy(&engine);
|
||||
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv *env, jclass, jlong nativeEngine) {
|
||||
wrapJni(env, [=]() {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Engine::destroy(&engine);
|
||||
});
|
||||
}
|
||||
|
||||
// SwapChain
|
||||
@@ -77,11 +83,13 @@ Java_com_google_android_filament_Engine_nCreateSwapChainFromRawPointer(JNIEnv*,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroySwapChain(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroySwapChain(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeSwapChain) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
|
||||
return engine->destroy(swapChain);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(swapChain);
|
||||
});
|
||||
}
|
||||
|
||||
// View
|
||||
@@ -94,11 +102,13 @@ Java_com_google_android_filament_Engine_nCreateView(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyView(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyView(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeView) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
View* view = (View*) nativeView;
|
||||
return engine->destroy(view);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(view);
|
||||
});
|
||||
}
|
||||
|
||||
// Renderer
|
||||
@@ -111,11 +121,13 @@ Java_com_google_android_filament_Engine_nCreateRenderer(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyRenderer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyRenderer(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeRenderer) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Renderer* renderer = (Renderer*) nativeRenderer;
|
||||
return engine->destroy(renderer);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(renderer);
|
||||
});
|
||||
}
|
||||
|
||||
// Camera
|
||||
@@ -137,11 +149,13 @@ Java_com_google_android_filament_Engine_nGetCameraComponent(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyCameraComponent(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyCameraComponent(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jint entity_) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Entity& entity = *reinterpret_cast<Entity*>(&entity_);
|
||||
engine->destroyCameraComponent(entity);
|
||||
wrapJni(env, [=]() {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Entity entity = *reinterpret_cast<const Entity*>(&entity_);
|
||||
engine->destroyCameraComponent(entity);
|
||||
});
|
||||
}
|
||||
|
||||
// Scene
|
||||
@@ -154,11 +168,13 @@ Java_com_google_android_filament_Engine_nCreateScene(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyScene(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyScene(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeScene) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
return engine->destroy(scene);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(scene);
|
||||
});
|
||||
}
|
||||
|
||||
// Fence
|
||||
@@ -171,119 +187,147 @@ Java_com_google_android_filament_Engine_nCreateFence(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyFence(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyFence(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeFence) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Fence* fence = (Fence*) nativeFence;
|
||||
return engine->destroy(fence);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(fence);
|
||||
});
|
||||
}
|
||||
|
||||
// Stream
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyStream(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyStream(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeStream) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Stream* stream = (Stream*) nativeStream;
|
||||
return engine->destroy(stream);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(stream);
|
||||
});
|
||||
}
|
||||
|
||||
// Others...
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyIndexBuffer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyIndexBuffer(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeIndexBuffer) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
IndexBuffer* indexBuffer = (IndexBuffer*) nativeIndexBuffer;
|
||||
return engine->destroy(indexBuffer);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(indexBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyVertexBuffer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyVertexBuffer(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeVertexBuffer) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
VertexBuffer* vertexBuffer = (VertexBuffer*) nativeVertexBuffer;
|
||||
return engine->destroy(vertexBuffer);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(vertexBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroySkinningBuffer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroySkinningBuffer(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeSkinningBuffer) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
SkinningBuffer* skinningBuffer = (SkinningBuffer*) nativeSkinningBuffer;
|
||||
return engine->destroy(skinningBuffer);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(skinningBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyMorphTargetBuffer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyMorphTargetBuffer(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeMorphTargetBuffer) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
MorphTargetBuffer* mtb = (MorphTargetBuffer*) nativeMorphTargetBuffer;
|
||||
return engine->destroy(mtb);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(mtb);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyIndirectLight(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyIndirectLight(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeIndirectLight) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
IndirectLight* indirectLight = (IndirectLight*) nativeIndirectLight;
|
||||
return engine->destroy(indirectLight);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(indirectLight);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyMaterial(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyMaterial(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeMaterial) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
return engine->destroy(material);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(material);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyMaterialInstance(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyMaterialInstance(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeMaterialInstance) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
MaterialInstance* materialInstance = (MaterialInstance*) nativeMaterialInstance;
|
||||
return engine->destroy(materialInstance);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(materialInstance);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroySkybox(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroySkybox(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeSkybox) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Skybox* skybox = (Skybox*) nativeSkybox;
|
||||
return engine->destroy(skybox);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(skybox);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyColorGrading(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyColorGrading(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeColorGrading) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
ColorGrading* colorGrading = (ColorGrading*) nativeColorGrading;
|
||||
return engine->destroy(colorGrading);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(colorGrading);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyTexture(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyTexture(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeTexture) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
return engine->destroy(texture);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(texture);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyRenderTarget(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyRenderTarget(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong nativeTarget) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
RenderTarget* target = (RenderTarget*) nativeTarget;
|
||||
return engine->destroy(target);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->destroy(target);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nDestroyEntity(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nDestroyEntity(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jint entity_) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Entity& entity = *reinterpret_cast<Entity*>(&entity_);
|
||||
engine->destroy(entity);
|
||||
wrapJni(env, [=]() {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Entity entity = *reinterpret_cast<const Entity*>(&entity_);
|
||||
engine->destroy(entity);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -415,17 +459,21 @@ Java_com_google_android_filament_Engine_nIsValidSwapChain(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jlong timeout) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return engine->flushAndWait((uint64_t)timeout);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return engine->flushAndWait((uint64_t)timeout);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Engine_nFlush(JNIEnv *env, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->flush();
|
||||
wrapJni(env, [=]() {
|
||||
engine->flush();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
@@ -436,21 +484,32 @@ Java_com_google_android_filament_Engine_nIsPaused(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nCompile(JNIEnv* env, jclass,
|
||||
Java_com_google_android_filament_Engine_nCompile(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jint priority, jlong nativeMaterial, jlong nativeView,
|
||||
jint shadowReceiver, jint skinning, jobject handler, jobject runnable) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
View* view = (View*) nativeView;
|
||||
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
|
||||
engine->compile(
|
||||
(backend::CompilerPriorityQueue) priority,
|
||||
material, view,
|
||||
(utils::tribool::value_t) shadowReceiver,
|
||||
(utils::tribool::value_t) skinning,
|
||||
jniCallback->getHandler(), [jniCallback](Material*){
|
||||
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||
});
|
||||
wrapJni(env, [=]() {
|
||||
#if defined(__EXCEPTIONS)
|
||||
try {
|
||||
#endif
|
||||
engine->compile(
|
||||
(backend::CompilerPriorityQueue) priority,
|
||||
material, view,
|
||||
(utils::tribool::value_t) shadowReceiver,
|
||||
(utils::tribool::value_t) skinning,
|
||||
jniCallback->getHandler(), [jniCallback](Material*){
|
||||
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||
});
|
||||
#if defined(__EXCEPTIONS)
|
||||
} catch (...) {
|
||||
JniCallback::destroy(jniCallback);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -511,6 +570,12 @@ Java_com_google_android_filament_Engine_nIsAutomaticInstancingEnabled(JNIEnv*, j
|
||||
return (jboolean)engine->isAutomaticInstancingEnabled();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nHasUnrecoverableFailure(JNIEnv*, jclass, jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jboolean)engine->hasUnrecoverableFailure();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Engine_nGetMaxStereoscopicEyes(JNIEnv*, jclass, jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
@@ -526,10 +591,12 @@ Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jcla
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Engine_nSetActiveFeatureLevel(JNIEnv *, jclass,
|
||||
Java_com_google_android_filament_Engine_nSetActiveFeatureLevel(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jint ordinal) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jint)engine->setActiveFeatureLevel((Engine::FeatureLevel)ordinal);
|
||||
return wrapJni<jint>(env, [=]() {
|
||||
return (jint)engine->setActiveFeatureLevel((Engine::FeatureLevel)ordinal);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -651,9 +718,11 @@ Java_com_google_android_filament_Engine_nSetBuilderFeature(JNIEnv *env, jclass c
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) {
|
||||
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv *env, jclass, jlong nativeBuilder) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
return (jlong) builder->build();
|
||||
return wrapJniBackend<jlong>(env, [=]() {
|
||||
return (jlong) builder->build();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <filament/Fence.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -24,13 +25,17 @@ extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Fence_nWait(JNIEnv *env, jclass type, jlong nativeFence, jint mode,
|
||||
jlong timeoutNanoSeconds) {
|
||||
Fence *fence = (Fence *) nativeFence;
|
||||
return (jint) fence->wait((Fence::Mode) mode, (uint64_t) timeoutNanoSeconds);
|
||||
return filament::android::wrapJniBackend<jint>(env, [=]() {
|
||||
return (jint) fence->wait((Fence::Mode) mode, (uint64_t) timeoutNanoSeconds);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Fence_nWaitAndDestroy(JNIEnv *env, jclass type, jlong nativeFence,
|
||||
jint mode) {
|
||||
Fence *fence = (Fence *) nativeFence;
|
||||
return (jint) Fence::waitAndDestroy(fence, (Fence::Mode) mode);
|
||||
return filament::android::wrapJniBackend<jint>(env, [=]() {
|
||||
return (jint) Fence::waitAndDestroy(fence, (Fence::Mode) mode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#include <backend/BufferDescriptor.h>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_IndexBuffer_nCreateBuilder(JNIEnv *env, jclass type) {
|
||||
@@ -63,7 +64,9 @@ Java_com_google_android_filament_IndexBuffer_nBuilderBuild(JNIEnv *env, jclass t
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
IndexBuffer::Builder* builder = (IndexBuffer::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -94,7 +97,9 @@ Java_com_google_android_filament_IndexBuffer_nSetBuffer(JNIEnv *env, jclass type
|
||||
BufferDescriptor desc(data, sizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
indexBuffer->setBuffer(*engine, std::move(desc), (uint32_t) destOffsetInBytes);
|
||||
wrapJni(env, [&]() {
|
||||
indexBuffer->setBuffer(*engine, std::move(desc), (uint32_t) destOffsetInBytes);
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <common/NioUtils.h>
|
||||
#include <common/CallbackUtils.h>
|
||||
#include <math/mat4.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -37,11 +38,13 @@ Java_com_google_android_filament_IndirectLight_nDestroyBuilder(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_IndirectLight_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_IndirectLight_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
IndirectLight::Builder* builder = (IndirectLight::Builder*) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <filament/LightManager.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
|
||||
@@ -24,6 +25,7 @@
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_LightManager_nGetComponentCount(JNIEnv*, jclass,
|
||||
@@ -210,11 +212,13 @@ Java_com_google_android_filament_LightManager_nBuilderLightChannel(JNIEnv*, jcla
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_LightManager_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_LightManager_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine, jint entity) {
|
||||
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return jboolean(builder->build(*engine, (Entity &) entity) == LightManager::Builder::Success);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return jboolean(builder->build(*engine, (Entity &) entity) == LightManager::Builder::Success);
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -223,7 +227,9 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_LightManager_nComputeUniformSplits(JNIEnv* env, jclass,
|
||||
jfloatArray splitPositions, jint cascades) {
|
||||
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
|
||||
LightManager::ShadowCascades::computeUniformSplits(nativeSplits, (uint8_t) cascades);
|
||||
wrapJni(env, [=]() {
|
||||
LightManager::ShadowCascades::computeUniformSplits(nativeSplits, (uint8_t) cascades);
|
||||
});
|
||||
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
|
||||
}
|
||||
|
||||
@@ -231,7 +237,9 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_LightManager_nComputeLogSplits(JNIEnv* env, jclass,
|
||||
jfloatArray splitPositions, jint cascades, jfloat near, jfloat far) {
|
||||
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
|
||||
LightManager::ShadowCascades::computeLogSplits(nativeSplits, (uint8_t) cascades, near, far);
|
||||
wrapJni(env, [=]() {
|
||||
LightManager::ShadowCascades::computeLogSplits(nativeSplits, (uint8_t) cascades, near, far);
|
||||
});
|
||||
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
|
||||
}
|
||||
|
||||
@@ -239,7 +247,9 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_LightManager_nComputePracticalSplits(JNIEnv* env, jclass,
|
||||
jfloatArray splitPositions, jint cascades, jfloat near, jfloat far, jfloat lambda) {
|
||||
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
|
||||
LightManager::ShadowCascades::computePracticalSplits(nativeSplits, (uint8_t) cascades, near, far, lambda);
|
||||
wrapJni(env, [=]() {
|
||||
LightManager::ShadowCascades::computePracticalSplits(nativeSplits, (uint8_t) cascades, near, far, lambda);
|
||||
});
|
||||
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,25 +20,28 @@
|
||||
|
||||
#include "common/NioUtils.h"
|
||||
#include "common/CallbackUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount, jint shadowQuality, jint uboBatchingMode) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
AutoBuffer buffer(env, buffer_, size);
|
||||
auto builder = Material::Builder();
|
||||
if (shBandCount) {
|
||||
builder.sphericalHarmonicsBandCount(shBandCount);
|
||||
}
|
||||
builder.shadowSamplingQuality((Material::Builder::ShadowSamplingQuality)shadowQuality);
|
||||
builder.uboBatching((Material::UboBatchingMode)uboBatchingMode);
|
||||
Material* material = builder
|
||||
.package(buffer.getData(), buffer.getSize())
|
||||
.build(*engine);
|
||||
|
||||
return (jlong) material;
|
||||
return wrapJni<jlong>(env, [=]() {
|
||||
AutoBuffer buffer(env, buffer_, size);
|
||||
auto builder = Material::Builder();
|
||||
if (shBandCount) {
|
||||
builder.sphericalHarmonicsBandCount(shBandCount);
|
||||
}
|
||||
builder.shadowSamplingQuality((Material::Builder::ShadowSamplingQuality)shadowQuality);
|
||||
builder.uboBatching((Material::UboBatchingMode)uboBatchingMode);
|
||||
Material* material = builder
|
||||
.package(buffer.getData(), buffer.getSize())
|
||||
.build(*engine);
|
||||
return (jlong) material;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace filament::android;
|
||||
|
||||
enum BooleanElement {
|
||||
BOOL,
|
||||
@@ -56,7 +58,9 @@ template<typename T>
|
||||
static void setParameter(JNIEnv* env, jlong nativeMaterialInstance, jstring name_, T v) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setParameter(name, v);
|
||||
wrapJni(env, [=]() {
|
||||
instance->setParameter(name, v);
|
||||
});
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
@@ -160,20 +164,22 @@ Java_com_google_android_filament_MaterialInstance_nSetBooleanParameterArray(JNIE
|
||||
// NOTE: In C++, bool has an implementation-defined size. Here we assume
|
||||
// it has the same size as jboolean, which is 1 byte.
|
||||
|
||||
switch ((BooleanElement) element) {
|
||||
case BOOL:
|
||||
instance->setParameter(name, ((const bool*) v) + offset, count);
|
||||
break;
|
||||
case BOOL2:
|
||||
instance->setParameter(name, ((const bool2*) v) + offset, count);
|
||||
break;
|
||||
case BOOL3:
|
||||
instance->setParameter(name, ((const bool3*) v) + offset, count);
|
||||
break;
|
||||
case BOOL4:
|
||||
instance->setParameter(name, ((const bool4*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
wrapJni(env, [=]() {
|
||||
switch ((BooleanElement) element) {
|
||||
case BOOL:
|
||||
instance->setParameter(name, ((const bool*) v) + offset, count);
|
||||
break;
|
||||
case BOOL2:
|
||||
instance->setParameter(name, ((const bool2*) v) + offset, count);
|
||||
break;
|
||||
case BOOL3:
|
||||
instance->setParameter(name, ((const bool3*) v) + offset, count);
|
||||
break;
|
||||
case BOOL4:
|
||||
instance->setParameter(name, ((const bool4*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
env->ReleaseBooleanArrayElements(v_, v, 0);
|
||||
|
||||
@@ -190,20 +196,22 @@ Java_com_google_android_filament_MaterialInstance_nSetIntParameterArray(JNIEnv *
|
||||
const char* name = env->GetStringUTFChars(name_, 0);
|
||||
jint* v = env->GetIntArrayElements(v_, NULL);
|
||||
|
||||
switch ((IntElement) element) {
|
||||
case INT:
|
||||
instance->setParameter(name, ((const int32_t*) v) + offset, count);
|
||||
break;
|
||||
case INT2:
|
||||
instance->setParameter(name, ((const int2*) v) + offset, count);
|
||||
break;
|
||||
case INT3:
|
||||
instance->setParameter(name, ((const int3*) v) + offset, count);
|
||||
break;
|
||||
case INT4:
|
||||
instance->setParameter(name, ((const int4*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
wrapJni(env, [=]() {
|
||||
switch ((IntElement) element) {
|
||||
case INT:
|
||||
instance->setParameter(name, ((const int32_t*) v) + offset, count);
|
||||
break;
|
||||
case INT2:
|
||||
instance->setParameter(name, ((const int2*) v) + offset, count);
|
||||
break;
|
||||
case INT3:
|
||||
instance->setParameter(name, ((const int3*) v) + offset, count);
|
||||
break;
|
||||
case INT4:
|
||||
instance->setParameter(name, ((const int4*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
env->ReleaseIntArrayElements(v_, v, JNI_ABORT);
|
||||
|
||||
@@ -220,26 +228,28 @@ Java_com_google_android_filament_MaterialInstance_nSetFloatParameterArray(JNIEnv
|
||||
const char* name = env->GetStringUTFChars(name_, 0);
|
||||
jfloat* v = env->GetFloatArrayElements(v_, NULL);
|
||||
|
||||
switch ((FloatElement) element) {
|
||||
case FLOAT:
|
||||
instance->setParameter(name, ((const float*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT2:
|
||||
instance->setParameter(name, ((const float2*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT3:
|
||||
instance->setParameter(name, ((const float3*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT4:
|
||||
instance->setParameter(name, ((const float4*) v) + offset, count);
|
||||
break;
|
||||
case MAT3:
|
||||
instance->setParameter(name, ((const mat3f*) v) + offset, count);
|
||||
break;
|
||||
case MAT4:
|
||||
instance->setParameter(name, ((const mat4f*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
wrapJni(env, [=]() {
|
||||
switch ((FloatElement) element) {
|
||||
case FLOAT:
|
||||
instance->setParameter(name, ((const float*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT2:
|
||||
instance->setParameter(name, ((const float2*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT3:
|
||||
instance->setParameter(name, ((const float3*) v) + offset, count);
|
||||
break;
|
||||
case FLOAT4:
|
||||
instance->setParameter(name, ((const float4*) v) + offset, count);
|
||||
break;
|
||||
case MAT3:
|
||||
instance->setParameter(name, ((const mat3f*) v) + offset, count);
|
||||
break;
|
||||
case MAT4:
|
||||
instance->setParameter(name, ((const mat4f*) v) + offset, count);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
env->ReleaseFloatArrayElements(v_, v, 0);
|
||||
|
||||
@@ -260,7 +270,9 @@ Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setParameter(name, texture, JniUtils::from_long(sampler_));
|
||||
wrapJni(env, [=]() {
|
||||
instance->setParameter(name, texture, JniUtils::from_long(sampler_));
|
||||
});
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -24,6 +23,7 @@
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
@@ -81,11 +81,13 @@ extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_MorphTargetBuffer_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_MorphTargetBuffer_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
MorphTargetBuffer::Builder* builder = (MorphTargetBuffer::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -97,11 +99,13 @@ Java_com_google_android_filament_MorphTargetBuffer_nSetPositionsAt(JNIEnv* env,
|
||||
jint targetIndex, jfloatArray positions, jint count) {
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeObject;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
jfloat* data = env->GetFloatArrayElements(positions, NULL);
|
||||
morphTargetBuffer->setPositionsAt(*engine, targetIndex,
|
||||
(math::float4*) data, size_t(count));
|
||||
env->ReleaseFloatArrayElements(positions, data, JNI_ABORT);
|
||||
return 0;
|
||||
return filament::android::wrapJni<jint>(env, [=]() {
|
||||
jfloat* data = env->GetFloatArrayElements(positions, NULL);
|
||||
morphTargetBuffer->setPositionsAt(*engine, targetIndex,
|
||||
(math::float4*) data, size_t(count));
|
||||
env->ReleaseFloatArrayElements(positions, data, JNI_ABORT);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -111,11 +115,13 @@ Java_com_google_android_filament_MorphTargetBuffer_nSetTangentsAt(JNIEnv* env, j
|
||||
jint targetIndex, jshortArray tangents, jint count) {
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeObject;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
jshort* data = env->GetShortArrayElements(tangents, NULL);
|
||||
morphTargetBuffer->setTangentsAt(*engine, targetIndex,
|
||||
(math::short4*) data, size_t(count));
|
||||
env->ReleaseShortArrayElements(tangents, data, JNI_ABORT);
|
||||
return 0;
|
||||
return filament::android::wrapJni<jint>(env, [=]() {
|
||||
jshort* data = env->GetShortArrayElements(tangents, NULL);
|
||||
morphTargetBuffer->setTangentsAt(*engine, targetIndex,
|
||||
(math::short4*) data, size_t(count));
|
||||
env->ReleaseShortArrayElements(tangents, data, JNI_ABORT);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <filament/RenderTarget.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
@@ -72,7 +73,9 @@ Java_com_google_android_filament_RenderTarget_nBuilderBuild(JNIEnv *env, jclass
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
RenderTarget::Builder* builder = (RenderTarget::Builder*) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nHasComponent(JNIEnv*, jclass,
|
||||
@@ -63,11 +65,13 @@ Java_com_google_android_filament_RenderableManager_nDestroyBuilder(JNIEnv*, jcla
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine, jint entity) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return jboolean(builder->build(*engine, (Entity &) entity) == RenderableManager::Builder::Success);
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
return jboolean(builder->build(*engine, (Entity &) entity) == RenderableManager::Builder::Success);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -276,11 +280,13 @@ Java_com_google_android_filament_RenderableManager_nBuilderInstances(JNIEnv*, jc
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nSetSkinningBuffer(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_RenderableManager_nSetSkinningBuffer(JNIEnv* env, jclass,
|
||||
jlong nativeRenderableManager, jint i, jlong nativeSkinningBuffer, jint count, jint offset) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
SkinningBuffer *sb = (SkinningBuffer *) nativeSkinningBuffer;
|
||||
rm->setSkinningBuffer(i, sb, count, offset);
|
||||
wrapJni(env, [=]() {
|
||||
rm->setSkinningBuffer(i, sb, count, offset);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -295,9 +301,12 @@ Java_com_google_android_filament_RenderableManager_nSetBonesAsMatrices(JNIEnv* e
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
rm->setBones((RenderableManager::Instance)i,
|
||||
static_cast<filament::math::mat4f const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
jint result = 0;
|
||||
wrapJni(env, [=]() {
|
||||
rm->setBones((RenderableManager::Instance)i,
|
||||
static_cast<filament::math::mat4f const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -312,9 +321,12 @@ Java_com_google_android_filament_RenderableManager_nSetBonesAsQuaternions(JNIEnv
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
rm->setBones((RenderableManager::Instance)i,
|
||||
static_cast<RenderableManager::Bone const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
jint result = 0;
|
||||
wrapJni(env, [=]() {
|
||||
rm->setBones((RenderableManager::Instance)i,
|
||||
static_cast<RenderableManager::Bone const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -323,17 +335,21 @@ Java_com_google_android_filament_RenderableManager_nSetMorphWeights(JNIEnv* env,
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
jfloat* vec = env->GetFloatArrayElements(weights, NULL);
|
||||
jsize count = env->GetArrayLength(weights);
|
||||
rm->setMorphWeights((RenderableManager::Instance)instance, vec, count, offset);
|
||||
wrapJni(env, [=]() {
|
||||
rm->setMorphWeights((RenderableManager::Instance)instance, vec, count, offset);
|
||||
});
|
||||
env->ReleaseFloatArrayElements(weights, vec, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferOffsetAt(JNIEnv*,
|
||||
Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferOffsetAt(JNIEnv* env,
|
||||
jclass, jlong nativeRenderableManager, jint i, int level, jint primitiveIndex,
|
||||
jlong, jint offset) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
rm->setMorphTargetBufferOffsetAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, (size_t) offset);
|
||||
wrapJni(env, [=]() {
|
||||
rm->setMorphTargetBufferOffsetAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, (size_t) offset);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -344,12 +360,14 @@ Java_com_google_android_filament_RenderableManager_nGetMorphTargetCount(JNIEnv*
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nSetAxisAlignedBoundingBox(JNIEnv*,
|
||||
Java_com_google_android_filament_RenderableManager_nSetAxisAlignedBoundingBox(JNIEnv* env,
|
||||
jclass, jlong nativeRenderableManager, jint i, jfloat cx, jfloat cy, jfloat cz,
|
||||
jfloat ex, jfloat ey, jfloat ez) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
rm->setAxisAlignedBoundingBox((RenderableManager::Instance) i, {{cx, cy, cz},
|
||||
{ex, ey, ez}});
|
||||
wrapJni(env, [=]() {
|
||||
rm->setAxisAlignedBoundingBox((RenderableManager::Instance) i, {{cx, cy, cz},
|
||||
{ex, ey, ez}});
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -486,19 +504,23 @@ Java_com_google_android_filament_RenderableManager_nGetInstanceCount(JNIEnv*, jc
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nSetMaterialInstanceAt(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_RenderableManager_nSetMaterialInstanceAt(JNIEnv* env, jclass,
|
||||
jlong nativeRenderableManager, jint i, jint primitiveIndex, jlong nativeMaterialInstance) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
const MaterialInstance *materialInstance = (const MaterialInstance *) nativeMaterialInstance;
|
||||
rm->setMaterialInstanceAt((RenderableManager::Instance) i, (size_t) primitiveIndex,
|
||||
materialInstance);
|
||||
wrapJni(env, [=]() {
|
||||
rm->setMaterialInstanceAt((RenderableManager::Instance) i, (size_t) primitiveIndex,
|
||||
materialInstance);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nClearMaterialInstanceAt(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_RenderableManager_nClearMaterialInstanceAt(JNIEnv* env, jclass,
|
||||
jlong nativeRenderableManager, jint i, jint primitiveIndex) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
rm->clearMaterialInstanceAt((RenderableManager::Instance) i, (size_t) primitiveIndex);
|
||||
wrapJni(env, [=]() {
|
||||
rm->clearMaterialInstanceAt((RenderableManager::Instance) i, (size_t) primitiveIndex);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
|
||||
@@ -22,18 +22,24 @@
|
||||
#include <filament/Viewport.h>
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include "common/JniUtils.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
using namespace filament::android;
|
||||
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSkipFrame(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
Java_com_google_android_filament_Renderer_nSkipFrame(JNIEnv *env, jclass, jlong nativeRenderer,
|
||||
jlong vsyncSteadyClockTimeNano) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->skipFrame(uint64_t(vsyncSteadyClockTimeNano));
|
||||
wrapJni(env, [=]() {
|
||||
renderer->skipFrame(uint64_t(vsyncSteadyClockTimeNano));
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
@@ -43,37 +49,45 @@ Java_com_google_android_filament_Renderer_nShouldRenderFrame(JNIEnv *, jclass, j
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Renderer_nBeginFrame(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
Java_com_google_android_filament_Renderer_nBeginFrame(JNIEnv *env, jclass, jlong nativeRenderer,
|
||||
jlong nativeSwapChain, jlong frameTimeNanos) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
SwapChain *swapChain = (SwapChain *) nativeSwapChain;
|
||||
return (jboolean) renderer->beginFrame(swapChain, uint64_t(frameTimeNanos));
|
||||
return wrapJniBackend<jboolean>(env, [=]() {
|
||||
return (jboolean) renderer->beginFrame(swapChain, uint64_t(frameTimeNanos));
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nEndFrame(JNIEnv *, jclass, jlong nativeRenderer) {
|
||||
Java_com_google_android_filament_Renderer_nEndFrame(JNIEnv *env, jclass, jlong nativeRenderer) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->endFrame();
|
||||
wrapJniBackend(env, [=]() {
|
||||
renderer->endFrame();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nRender(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
Java_com_google_android_filament_Renderer_nRender(JNIEnv *env, jclass, jlong nativeRenderer,
|
||||
jlong nativeView) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
View *view = (View *) nativeView;
|
||||
renderer->render(view);
|
||||
wrapJniBackend(env, [=]() {
|
||||
renderer->render(view);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nRenderStandaloneView(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
Java_com_google_android_filament_Renderer_nRenderStandaloneView(JNIEnv *env, jclass, jlong nativeRenderer,
|
||||
jlong nativeView) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
View *view = (View *) nativeView;
|
||||
renderer->renderStandaloneView(view);
|
||||
wrapJni(env, [=]() {
|
||||
renderer->renderStandaloneView(view);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nCopyFrame(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
Java_com_google_android_filament_Renderer_nCopyFrame(JNIEnv *env, jclass, jlong nativeRenderer,
|
||||
jlong nativeDstSwapChain,
|
||||
jint dstLeft, jint dstBottom, jint dstWidth, jint dstHeight,
|
||||
jint srcLeft, jint srcBottom, jint srcWidth, jint srcHeight,
|
||||
@@ -82,7 +96,9 @@ Java_com_google_android_filament_Renderer_nCopyFrame(JNIEnv *, jclass, jlong nat
|
||||
SwapChain *dstSwapChain = (SwapChain *) nativeDstSwapChain;
|
||||
const filament::Viewport dstViewport {dstLeft, dstBottom, (uint32_t) dstWidth, (uint32_t) dstHeight};
|
||||
const filament::Viewport srcViewport {srcLeft, srcBottom, (uint32_t) srcWidth, (uint32_t) srcHeight};
|
||||
renderer->copyFrame(dstSwapChain, dstViewport, srcViewport, (uint32_t) flags);
|
||||
wrapJni(env, [=]() {
|
||||
renderer->copyFrame(dstSwapChain, dstViewport, srcViewport, (uint32_t) flags);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -114,10 +130,11 @@ Java_com_google_android_filament_Renderer_nReadPixels(JNIEnv *env, jclass,
|
||||
(uint32_t) stride,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
renderer->readPixels(uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
|
||||
std::move(desc));
|
||||
|
||||
return 0;
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
renderer->readPixels(uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
|
||||
std::move(desc));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -150,23 +167,28 @@ Java_com_google_android_filament_Renderer_nReadPixelsEx(JNIEnv *env, jclass,
|
||||
(uint32_t) stride,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
renderer->readPixels(renderTarget,
|
||||
uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
|
||||
std::move(desc));
|
||||
|
||||
return 0;
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
renderer->readPixels(renderTarget,
|
||||
uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
|
||||
std::move(desc));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jdouble JNICALL
|
||||
Java_com_google_android_filament_Renderer_nGetUserTime(JNIEnv*, jclass, jlong nativeRenderer) {
|
||||
Java_com_google_android_filament_Renderer_nGetUserTime(JNIEnv *env, jclass, jlong nativeRenderer) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
return renderer->getUserTime();
|
||||
return wrapJni<jdouble>(env, [=]() {
|
||||
return renderer->getUserTime();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nResetUserTime(JNIEnv*, jclass, jlong nativeRenderer) {
|
||||
Java_com_google_android_filament_Renderer_nResetUserTime(JNIEnv *env, jclass, jlong nativeRenderer) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->resetUserTime();
|
||||
wrapJni(env, [=]() {
|
||||
renderer->resetUserTime();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -186,20 +208,24 @@ Java_com_google_android_filament_Renderer_nSetFrameRateOptions(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSetClearOptions(JNIEnv *, jclass ,
|
||||
Java_com_google_android_filament_Renderer_nSetClearOptions(JNIEnv *env, jclass ,
|
||||
jlong nativeRenderer, jfloat r, jfloat g, jfloat b, jfloat a,
|
||||
jboolean clear, jboolean discard) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setClearOptions({ .clearColor = {r, g, b, a},
|
||||
.clear = (bool) clear,
|
||||
.discard = (bool) discard});
|
||||
wrapJni(env, [=]() {
|
||||
renderer->setClearOptions({ .clearColor = {r, g, b, a},
|
||||
.clear = (bool) clear,
|
||||
.discard = (bool) discard});
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass ,
|
||||
Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *env, jclass ,
|
||||
jlong nativeRenderer, jlong monotonicClockNanos) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setPresentationTime(monotonicClockNanos);
|
||||
wrapJni(env, [=]() {
|
||||
renderer->setPresentationTime(monotonicClockNanos);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#include <filament/Scene.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Scene_nSetSkybox(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
@@ -43,15 +45,20 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Scene_nAddEntity(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
jint entity) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
scene->addEntity((Entity&) entity);
|
||||
wrapJni(env, [=]() {
|
||||
scene->addEntity((Entity&) entity);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Scene_nAddEntities(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
jintArray entities) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
jsize length = env->GetArrayLength(entities);
|
||||
Entity* nativeEntities = (Entity*) env->GetIntArrayElements(entities, nullptr);
|
||||
scene->addEntities(nativeEntities, env->GetArrayLength(entities));
|
||||
wrapJni(env, [=]() {
|
||||
scene->addEntities(nativeEntities, length);
|
||||
});
|
||||
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
||||
}
|
||||
|
||||
@@ -59,15 +66,20 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Scene_nRemove(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
jint entity) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
scene->remove((Entity&) entity);
|
||||
wrapJni(env, [=]() {
|
||||
scene->remove((Entity&) entity);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Scene_nRemoveEntities(JNIEnv *env, jclass type, jlong nativeScene,
|
||||
jintArray entities) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
jsize length = env->GetArrayLength(entities);
|
||||
Entity* nativeEntities = (Entity*) env->GetIntArrayElements(entities, nullptr);
|
||||
scene->removeEntities(nativeEntities, env->GetArrayLength(entities));
|
||||
wrapJni(env, [=]() {
|
||||
scene->removeEntities(nativeEntities, length);
|
||||
});
|
||||
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -24,6 +23,7 @@
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
@@ -60,11 +60,13 @@ Java_com_google_android_filament_SkinningBuffer_nBuilderInitialize(JNIEnv*, jcla
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_SkinningBuffer_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_SkinningBuffer_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
SkinningBuffer::Builder* builder = (SkinningBuffer::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -76,16 +78,18 @@ Java_com_google_android_filament_SkinningBuffer_nSetBonesAsMatrices(JNIEnv* env,
|
||||
jint offset) {
|
||||
SkinningBuffer *skinningBuffer = (SkinningBuffer *) nativeSkinningBuffer;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
AutoBuffer nioBuffer(env, matrices, boneCount * 16);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
skinningBuffer->setBones(*engine,
|
||||
static_cast<filament::math::mat4f const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
return filament::android::wrapJni<jint>(env, [=]() {
|
||||
AutoBuffer nioBuffer(env, matrices, boneCount * 16);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
skinningBuffer->setBones(*engine,
|
||||
static_cast<filament::math::mat4f const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -95,16 +99,18 @@ Java_com_google_android_filament_SkinningBuffer_nSetBonesAsQuaternions(JNIEnv* e
|
||||
jint boneCount, jint offset) {
|
||||
SkinningBuffer *skinningBuffer = (SkinningBuffer *) nativeSkinningBuffer;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
AutoBuffer nioBuffer(env, quaternions, boneCount * 8);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
skinningBuffer->setBones(*engine,
|
||||
static_cast<RenderableManager::Bone const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
return filament::android::wrapJni<jint>(env, [=]() {
|
||||
AutoBuffer nioBuffer(env, quaternions, boneCount * 8);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
skinningBuffer->setBones(*engine,
|
||||
static_cast<RenderableManager::Bone const *>(data), (size_t)boneCount, (size_t)offset);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <filament/Skybox.h>
|
||||
|
||||
#include <math/vec4.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -76,7 +77,9 @@ Java_com_google_android_filament_Skybox_nBuilderBuild(JNIEnv *env, jclass type,
|
||||
jlong nativeSkyBoxBuilder, jlong nativeEngine) {
|
||||
Skybox::Builder *builder = (Skybox::Builder *) nativeSkyBoxBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "common/NioUtils.h"
|
||||
#include "common/CallbackUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
@@ -113,11 +114,13 @@ Java_com_google_android_filament_Stream_nBuilderHeight(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Stream_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Stream_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeStreamBuilder, jlong nativeEngine) {
|
||||
StreamBuilder* builder = (StreamBuilder*) nativeStreamBuilder;
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jlong) builder->builder()->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->builder()->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "common/NioUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::geometry;
|
||||
@@ -125,7 +126,9 @@ extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_SurfaceOrientation_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder) {
|
||||
auto wrapper = (JniWrapper *) nativeBuilder;
|
||||
return (jlong) wrapper->builder->build();
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) wrapper->builder->build();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <filament/SwapChain.h>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -58,11 +59,13 @@ Java_com_google_android_filament_SwapChain_nSetFrameScheduledCallback(JNIEnv* en
|
||||
jlong nativeSwapChain, jobject handler, jobject runnable) {
|
||||
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
|
||||
auto* callback = JniCallback::make(env, handler, runnable);
|
||||
swapChain->setFrameScheduledCallback(callback->getHandler(),
|
||||
[callback](backend::PresentCallable) {
|
||||
// Ignore PresentCallable, which is only meaningful with the Metal backend.
|
||||
JniCallback::postToJavaAndDestroy(callback);
|
||||
});
|
||||
filament::android::wrapJni<void>(env, [=]() {
|
||||
swapChain->setFrameScheduledCallback(callback->getHandler(),
|
||||
[callback](backend::PresentCallable) {
|
||||
// Ignore PresentCallable, which is only meaningful with the Metal backend.
|
||||
JniCallback::postToJavaAndDestroy(callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/bitmap.h>
|
||||
@@ -38,12 +37,14 @@
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
using namespace filament::android;
|
||||
|
||||
static size_t getTextureDataSize(const Texture *texture,
|
||||
size_t level, Texture::Format format, Texture::Type type,
|
||||
@@ -273,12 +274,13 @@ Java_com_google_android_filament_Texture_nSetImage3D(JNIEnv* env, jclass, jlong
|
||||
(uint32_t) stride,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset, (uint32_t) zoffset,
|
||||
(uint32_t) width, (uint32_t) height, (uint32_t) depth,
|
||||
std::move(desc));
|
||||
|
||||
return 0;
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset, (uint32_t) zoffset,
|
||||
(uint32_t) width, (uint32_t) height, (uint32_t) depth,
|
||||
std::move(desc));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -307,12 +309,13 @@ Java_com_google_android_filament_Texture_nSetImage3DCompressed(JNIEnv *env, jcla
|
||||
(backend::CompressedPixelDataType) compressedFormat, (uint32_t) compressedSizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset, (uint32_t) zoffset,
|
||||
(uint32_t) width, (uint32_t) height, (uint32_t) depth,
|
||||
std::move(desc));
|
||||
|
||||
return 0;
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset, (uint32_t) zoffset,
|
||||
(uint32_t) width, (uint32_t) height, (uint32_t) depth,
|
||||
std::move(desc));
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -346,12 +349,13 @@ Java_com_google_android_filament_Texture_nSetImageCubemap(JNIEnv *env, jclass,
|
||||
(uint32_t) stride,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets);
|
||||
texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets);
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -384,20 +388,23 @@ Java_com_google_android_filament_Texture_nSetImageCubemapCompressed(JNIEnv *env,
|
||||
(backend::CompressedPixelDataType) compressedFormat, (uint32_t) compressedSizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets);
|
||||
texture->setImage(*engine, (size_t) level, std::move(desc), faceOffsets);
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetExternalImage(JNIEnv*, jclass, jlong nativeTexture,
|
||||
Java_com_google_android_filament_Texture_nSetExternalImage(JNIEnv* env, jclass, jlong nativeTexture,
|
||||
jlong nativeEngine, jlong eglImage) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
texture->setExternalImage(*engine, (void*)eglImage);
|
||||
wrapJni(env, [=]() {
|
||||
texture->setExternalImage(*engine, (void*)eglImage);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -418,33 +425,35 @@ Java_com_google_android_filament_Texture_nSetExternalImageByAHB(JNIEnv *env, jcl
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (engine->getBackend() == Backend::OPENGL) {
|
||||
// CAVEAT: we assume that Backend::OPENGL on Android implies PlatformEGLAndroid.
|
||||
return wrapJni<jboolean>(env, [=]() {
|
||||
if (engine->getBackend() == Backend::OPENGL) {
|
||||
// CAVEAT: we assume that Backend::OPENGL on Android implies PlatformEGLAndroid.
|
||||
#if UTILS_HAS_RTTI
|
||||
if (!dynamic_cast<PlatformEGLAndroid*>(platform)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!dynamic_cast<PlatformEGLAndroid*>(platform)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
auto* eglPlatform = (PlatformEGLAndroid*) platform;
|
||||
auto ref = eglPlatform->createExternalImage(nativeBuffer, false);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
}
|
||||
auto* eglPlatform = (PlatformEGLAndroid*) platform;
|
||||
auto ref = eglPlatform->createExternalImage(nativeBuffer, false);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
}
|
||||
|
||||
#if FILAMENT_SUPPORTS_VULKAN
|
||||
else if (engine->getBackend() == Backend::VULKAN) {
|
||||
// CAVEAT: we assume that Backend::VULKAN on Android implies VulkanPlatformAndroid.
|
||||
else if (engine->getBackend() == Backend::VULKAN) {
|
||||
// CAVEAT: we assume that Backend::VULKAN on Android implies VulkanPlatformAndroid.
|
||||
#if UTILS_HAS_RTTI
|
||||
if (!dynamic_cast<VulkanPlatformAndroid*>(platform)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!dynamic_cast<VulkanPlatformAndroid*>(platform)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
auto* vulkanPlatform = (VulkanPlatformAndroid*) platform;
|
||||
auto ref = vulkanPlatform->createExternalImage(nativeBuffer, false);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
}
|
||||
auto* vulkanPlatform = (VulkanPlatformAndroid*) platform;
|
||||
auto ref = vulkanPlatform->createExternalImage(nativeBuffer, false);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
}
|
||||
#endif // FILAMENT_SUPPORTS_VULKAN
|
||||
// success!
|
||||
return JNI_TRUE;
|
||||
// success!
|
||||
return JNI_TRUE;
|
||||
});
|
||||
#else
|
||||
// other platforms could come here
|
||||
return JNI_FALSE;
|
||||
@@ -452,20 +461,24 @@ Java_com_google_android_filament_Texture_nSetExternalImageByAHB(JNIEnv *env, jcl
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetExternalStream(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Texture_nSetExternalStream(JNIEnv* env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jlong nativeStream) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
Stream *stream = (Stream *) nativeStream;
|
||||
texture->setExternalStream(*engine, stream);
|
||||
wrapJni(env, [=]() {
|
||||
texture->setExternalStream(*engine, stream);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nGenerateMipmaps(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_Texture_nGenerateMipmaps(JNIEnv* env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
texture->generateMipmaps(*engine);
|
||||
wrapJni(env, [=]() {
|
||||
texture->generateMipmaps(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -515,9 +528,10 @@ Java_com_google_android_filament_Texture_nGeneratePrefilterMipmap(JNIEnv *env, j
|
||||
options.sampleCount = sampleCount;
|
||||
options.mirror = mirror;
|
||||
|
||||
filament::generatePrefilterMipmap(texture, *engine, std::move(desc), faceOffsets, &options);
|
||||
|
||||
return 0;
|
||||
return wrapJni<jint>(env, [&]() {
|
||||
filament::generatePrefilterMipmap(texture, *engine, std::move(desc), faceOffsets, &options);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -640,10 +654,12 @@ Java_com_google_android_filament_android_TextureHelper_nSetBitmap(JNIEnv* env, j
|
||||
autoBitmap->getType(format),
|
||||
&AutoBitmap::invokeNoCallback, autoBitmap);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
(uint32_t) width, (uint32_t) height,
|
||||
std::move(desc));
|
||||
filament::android::wrapJni(env, [&]() {
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
(uint32_t) width, (uint32_t) height,
|
||||
std::move(desc));
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -663,10 +679,12 @@ Java_com_google_android_filament_android_TextureHelper_nSetBitmapWithCallback(JN
|
||||
autoBitmap->getType(format),
|
||||
autoBitmap->getHandler(), &AutoBitmap::invoke, autoBitmap);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
(uint32_t) width, (uint32_t) height,
|
||||
std::move(desc));
|
||||
filament::android::wrapJni(env, [&]() {
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
(uint32_t) width, (uint32_t) height,
|
||||
std::move(desc));
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,9 +22,11 @@
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace utils;
|
||||
using namespace filament;
|
||||
using namespace filament::android;
|
||||
|
||||
static_assert(sizeof(jint) == sizeof(Entity), "jint and Entity are not compatible!!");
|
||||
|
||||
@@ -45,12 +47,14 @@ Java_com_google_android_filament_TransformManager_nGetInstance(JNIEnv*, jclass,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_TransformManager_nCreate(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_TransformManager_nCreate(JNIEnv* env, jclass,
|
||||
jlong nativeTransformManager, jint entity_) {
|
||||
TransformManager* tm = (TransformManager*) nativeTransformManager;
|
||||
Entity& entity = *reinterpret_cast<Entity*>(&entity_);
|
||||
tm->create(entity);
|
||||
return tm->getInstance(entity);
|
||||
return wrapJni<jint>(env, [=]() {
|
||||
Entity entity = *reinterpret_cast<const Entity*>(&entity_);
|
||||
tm->create(entity);
|
||||
return tm->getInstance(entity);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -58,16 +62,18 @@ Java_com_google_android_filament_TransformManager_nCreateArray(JNIEnv* env,
|
||||
jclass, jlong nativeTransformManager, jint entity_, jint parent,
|
||||
jfloatArray localTransform_) {
|
||||
TransformManager* tm = (TransformManager*) nativeTransformManager;
|
||||
Entity& entity = *reinterpret_cast<Entity*>(&entity_);
|
||||
if (localTransform_) {
|
||||
jfloat *localTransform = env->GetFloatArrayElements(localTransform_, NULL);
|
||||
tm->create(entity, (TransformManager::Instance) parent,
|
||||
*reinterpret_cast<const filament::math::mat4f *>(localTransform));
|
||||
env->ReleaseFloatArrayElements(localTransform_, localTransform, JNI_ABORT);
|
||||
} else {
|
||||
tm->create(entity, (TransformManager::Instance) parent);
|
||||
}
|
||||
return tm->getInstance(entity);
|
||||
return wrapJni<jint>(env, [=]() {
|
||||
Entity entity = *reinterpret_cast<const Entity*>(&entity_);
|
||||
if (localTransform_) {
|
||||
jfloat *localTransform = env->GetFloatArrayElements(localTransform_, NULL);
|
||||
tm->create(entity, (TransformManager::Instance) parent,
|
||||
*reinterpret_cast<const filament::math::mat4f *>(localTransform));
|
||||
env->ReleaseFloatArrayElements(localTransform_, localTransform, JNI_ABORT);
|
||||
} else {
|
||||
tm->create(entity, (TransformManager::Instance) parent);
|
||||
}
|
||||
return tm->getInstance(entity);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -75,16 +81,18 @@ Java_com_google_android_filament_TransformManager_nCreateArrayFp64(JNIEnv* env,
|
||||
jclass, jlong nativeTransformManager, jint entity_, jint parent,
|
||||
jdoubleArray localTransform_) {
|
||||
TransformManager* tm = (TransformManager*) nativeTransformManager;
|
||||
Entity& entity = *reinterpret_cast<Entity*>(&entity_);
|
||||
if (localTransform_) {
|
||||
jdouble *localTransform = env->GetDoubleArrayElements(localTransform_, NULL);
|
||||
tm->create(entity, (TransformManager::Instance) parent,
|
||||
*reinterpret_cast<const filament::math::mat4 *>(localTransform));
|
||||
env->ReleaseDoubleArrayElements(localTransform_, localTransform, JNI_ABORT);
|
||||
} else {
|
||||
tm->create(entity, (TransformManager::Instance) parent);
|
||||
}
|
||||
return tm->getInstance(entity);
|
||||
return wrapJni<jint>(env, [=]() {
|
||||
Entity entity = *reinterpret_cast<const Entity*>(&entity_);
|
||||
if (localTransform_) {
|
||||
jdouble *localTransform = env->GetDoubleArrayElements(localTransform_, NULL);
|
||||
tm->create(entity, (TransformManager::Instance) parent,
|
||||
*reinterpret_cast<const filament::math::mat4 *>(localTransform));
|
||||
env->ReleaseDoubleArrayElements(localTransform_, localTransform, JNI_ABORT);
|
||||
} else {
|
||||
tm->create(entity, (TransformManager::Instance) parent);
|
||||
}
|
||||
return tm->getInstance(entity);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
@@ -82,11 +83,13 @@ Java_com_google_android_filament_VertexBuffer_nBuilderNormalized(JNIEnv*, jclass
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_VertexBuffer_nBuilderBuild(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_VertexBuffer_nBuilderBuild(JNIEnv* env, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
VertexBuffer::Builder* builder = (VertexBuffer::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jlong) builder->build(*engine);
|
||||
return filament::android::wrapJni<jlong>(env, [=]() {
|
||||
return (jlong) builder->build(*engine);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
@@ -104,30 +107,34 @@ Java_com_google_android_filament_VertexBuffer_nSetBufferAt(JNIEnv *env, jclass,
|
||||
VertexBuffer *vertexBuffer = (VertexBuffer *) nativeVertexBuffer;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
AutoBuffer nioBuffer(env, buffer, count);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
return filament::android::wrapJni<jint>(env, [=]() {
|
||||
AutoBuffer nioBuffer(env, buffer, count);
|
||||
void* data = nioBuffer.getData();
|
||||
size_t sizeInBytes = nioBuffer.getSize();
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto* callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
|
||||
auto* callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
|
||||
|
||||
BufferDescriptor desc(data, sizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
BufferDescriptor desc(data, sizeInBytes,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
vertexBuffer->setBufferAt(*engine, (uint8_t) bufferIndex, std::move(desc),
|
||||
(uint32_t) destOffsetInBytes);
|
||||
vertexBuffer->setBufferAt(*engine, (uint8_t) bufferIndex, std::move(desc),
|
||||
(uint32_t) destOffsetInBytes);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_VertexBuffer_nSetBufferObjectAt(JNIEnv*, jclass,
|
||||
Java_com_google_android_filament_VertexBuffer_nSetBufferObjectAt(JNIEnv* env, jclass,
|
||||
jlong nativeVertexBuffer, jlong nativeEngine, jint bufferIndex, jlong nativeBufferObject) {
|
||||
VertexBuffer *vertexBuffer = (VertexBuffer *) nativeVertexBuffer;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
BufferObject *bufferObject = (BufferObject *) nativeBufferObject;
|
||||
vertexBuffer->setBufferObjectAt(*engine, (uint8_t) bufferIndex, bufferObject);
|
||||
filament::android::wrapJni(env, [=]() {
|
||||
vertexBuffer->setBufferObjectAt(*engine, (uint8_t) bufferIndex, bufferObject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
#include <common/JniUtils.h>
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::android;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetName(JNIEnv* env, jclass, jlong nativeView, jstring name_) {
|
||||
@@ -35,10 +37,12 @@ Java_com_google_android_filament_View_nSetName(JNIEnv* env, jclass, jlong native
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetScene(JNIEnv*, jclass, jlong nativeView, jlong nativeScene) {
|
||||
Java_com_google_android_filament_View_nSetScene(JNIEnv* env, jclass, jlong nativeView, jlong nativeScene) {
|
||||
View* view = (View*) nativeView;
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
view->setScene(scene);
|
||||
wrapJni(env, [=]() {
|
||||
view->setScene(scene);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -549,21 +553,27 @@ Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetMaterialGlobal(JNIEnv * , jclass, jlong nativeView,
|
||||
Java_com_google_android_filament_View_nSetMaterialGlobal(JNIEnv *env, jclass, jlong nativeView,
|
||||
jint index, jfloat x, jfloat y, jfloat z, jfloat w) {
|
||||
View *view = (View *) nativeView;
|
||||
view->setMaterialGlobal((uint32_t)index, { x, y, z, w });
|
||||
wrapJni(env, [=]() {
|
||||
view->setMaterialGlobal((uint32_t)index, { x, y, z, w });
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nGetMaterialGlobal(JNIEnv *env, jclass clazz,
|
||||
jlong nativeView, jint index, jfloatArray out_) {
|
||||
jfloat* out = env->GetFloatArrayElements(out_, nullptr);
|
||||
View *view = (View *) nativeView;
|
||||
auto result = view->getMaterialGlobal(index);
|
||||
std::copy_n(result.v, 4, out);
|
||||
env->ReleaseFloatArrayElements(out_, out, 0);
|
||||
wrapJni(env, [=]() {
|
||||
auto result = view->getMaterialGlobal(index);
|
||||
jfloat* out = env->GetFloatArrayElements(out_, nullptr);
|
||||
if (out) {
|
||||
std::copy_n(result.v, 4, out);
|
||||
env->ReleaseFloatArrayElements(out_, out, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -91,6 +91,8 @@ public class BufferObject {
|
||||
* @return the newly created <code>BufferObject</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the BufferObject could not be created
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*
|
||||
* @see #setBuffer
|
||||
*/
|
||||
|
||||
@@ -321,8 +321,7 @@ public class Engine {
|
||||
* be initialized, for instance if it doesn't support the right version of OpenGL or
|
||||
* OpenGL ES.
|
||||
*
|
||||
* @exception IllegalStateException can be thrown if there isn't enough memory to
|
||||
* allocate the command buffer.
|
||||
* @throws Error if there isn't enough memory to allocate the command buffer.
|
||||
*/
|
||||
public Engine build() {
|
||||
long nativeEngine = nBuilderBuild(mNativeBuilder);
|
||||
@@ -729,6 +728,8 @@ public class Engine {
|
||||
*
|
||||
* @return the active feature level.
|
||||
*
|
||||
* @throws RuntimeException if the feature level cannot be set.
|
||||
*
|
||||
* @see Builder#featureLevel
|
||||
* @see #getSupportedFeatureLevel
|
||||
* @see #getActiveFeatureLevel
|
||||
@@ -775,6 +776,15 @@ public class Engine {
|
||||
return nIsAutomaticInstancingEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the engine has encountered an unrecoverable failure.
|
||||
*
|
||||
* @return true if an unrecoverable failure has occurred, false otherwise.
|
||||
*/
|
||||
public boolean hasUnrecoverableFailure() {
|
||||
return nHasUnrecoverableFailure(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration settings of this {@link Engine}.
|
||||
*
|
||||
@@ -1261,9 +1271,10 @@ public class Engine {
|
||||
* Destroys a {@link Material} and frees all its associated resources.
|
||||
* <p>
|
||||
* All {@link MaterialInstance} of the specified {@link Material} must be destroyed before
|
||||
* destroying it; if some {@link MaterialInstance} remain, this method fails silently.
|
||||
* destroying it.
|
||||
*
|
||||
* @param material the {@link Material} to destroy
|
||||
* @throws RuntimeException if some MaterialInstances remain.
|
||||
*/
|
||||
public void destroyMaterial(@NonNull Material material) {
|
||||
assertDestroy(nDestroyMaterial(getNativeObject(), material.getNativeObject()));
|
||||
@@ -1580,6 +1591,7 @@ public class Engine {
|
||||
private static native long nGetEntityManager(long nativeEngine);
|
||||
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
|
||||
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
|
||||
private static native boolean nHasUnrecoverableFailure(long nativeEngine);
|
||||
private static native long nGetMaxStereoscopicEyes(long nativeEngine);
|
||||
private static native int nGetSupportedFeatureLevel(long nativeEngine);
|
||||
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
|
||||
|
||||
@@ -38,7 +38,17 @@ public class Fence {
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side wait on the Fence.
|
||||
*
|
||||
* Blocks the current thread until the Fence signals.
|
||||
*
|
||||
* @param mode Whether the command stream is flushed before waiting or not.
|
||||
* @param timeoutNanoSeconds Wait time out in nanoseconds. Using a timeout of 0 is a way to query the state of the fence.
|
||||
* A timeout value of WAIT_FOR_EVER is used to disable the timeout.
|
||||
* @return FenceStatus::CONDITION_SATISFIED on success,
|
||||
* FenceStatus::TIMEOUT_EXPIRED if the time out expired or
|
||||
* FenceStatus::ERROR in other cases.
|
||||
* @throws Error if the backend thread encountered an unrecoverable error.
|
||||
*/
|
||||
public FenceStatus wait(@NonNull Mode mode, long timeoutNanoSeconds) {
|
||||
int nativeResult = nWait(getNativeObject(), mode.ordinal(), timeoutNanoSeconds);
|
||||
@@ -55,6 +65,15 @@ public class Fence {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side wait on a Fence and destroy the Fence.
|
||||
*
|
||||
* @param fence Fence object to wait on.
|
||||
* @param mode Whether the command stream is flushed before waiting or not.
|
||||
* @return FenceStatus::CONDITION_SATISFIED on success,
|
||||
* FenceStatus::ERROR otherwise.
|
||||
* @throws Error if the backend thread encountered an unrecoverable error.
|
||||
*/
|
||||
public static FenceStatus waitAndDestroy(@NonNull Fence fence, @NonNull Mode mode) {
|
||||
int nativeResult = nWaitAndDestroy(fence.getNativeObject(), mode.ordinal());
|
||||
switch (nativeResult) {
|
||||
|
||||
@@ -99,6 +99,7 @@ public class IndexBuffer {
|
||||
* @return the newly created <code>IndexBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the IndexBuffer could not be created
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of memory or other resources, or if a parameter to a builder function was invalid.
|
||||
*
|
||||
* @see #setBuffer
|
||||
*/
|
||||
|
||||
@@ -316,6 +316,8 @@ public class IndirectLight {
|
||||
* @return A newly created <code>IndirectLight</code>
|
||||
*
|
||||
* @exception IllegalStateException if a parameter to a builder function was invalid.
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*/
|
||||
@NonNull
|
||||
public IndirectLight build(@NonNull Engine engine) {
|
||||
|
||||
@@ -781,6 +781,7 @@ public class LightManager {
|
||||
*
|
||||
* @param engine Reference to the {@link Engine} to associate this light with.
|
||||
* @param entity Entity to add the light component to.
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of memory or other resources, or if a parameter to a builder function was invalid.
|
||||
*/
|
||||
public void build(@NonNull Engine engine, @Entity int entity) {
|
||||
if (!nBuilderBuild(mNativeBuilder, engine.getNativeObject(), entity)) {
|
||||
|
||||
@@ -476,6 +476,7 @@ public class Material {
|
||||
* @return the newly created object
|
||||
*
|
||||
* @exception IllegalStateException if the material could not be created
|
||||
* @throws RuntimeException if a parameter to a builder function was invalid.
|
||||
*/
|
||||
@NonNull
|
||||
public Material build(@NonNull Engine engine) {
|
||||
|
||||
+18
@@ -156,6 +156,7 @@ public class MaterialInstance {
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x) {
|
||||
nSetParameterBool(getNativeObject(), name, x);
|
||||
@@ -166,6 +167,7 @@ public class MaterialInstance {
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x) {
|
||||
nSetParameterFloat(getNativeObject(), name, x);
|
||||
@@ -176,6 +178,7 @@ public class MaterialInstance {
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x) {
|
||||
nSetParameterInt(getNativeObject(), name, x);
|
||||
@@ -187,6 +190,7 @@ public class MaterialInstance {
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y) {
|
||||
nSetParameterBool2(getNativeObject(), name, x, y);
|
||||
@@ -198,6 +202,7 @@ public class MaterialInstance {
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y) {
|
||||
nSetParameterFloat2(getNativeObject(), name, x, y);
|
||||
@@ -209,6 +214,7 @@ public class MaterialInstance {
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y) {
|
||||
nSetParameterInt2(getNativeObject(), name, x, y);
|
||||
@@ -221,6 +227,7 @@ public class MaterialInstance {
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y, boolean z) {
|
||||
nSetParameterBool3(getNativeObject(), name, x, y, z);
|
||||
@@ -233,6 +240,7 @@ public class MaterialInstance {
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y, float z) {
|
||||
nSetParameterFloat3(getNativeObject(), name, x, y, z);
|
||||
@@ -245,6 +253,7 @@ public class MaterialInstance {
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y, int z) {
|
||||
nSetParameterInt3(getNativeObject(), name, x, y, z);
|
||||
@@ -258,6 +267,7 @@ public class MaterialInstance {
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y, boolean z, boolean w) {
|
||||
nSetParameterBool4(getNativeObject(), name, x, y, z, w);
|
||||
@@ -271,6 +281,7 @@ public class MaterialInstance {
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y, float z, float w) {
|
||||
nSetParameterFloat4(getNativeObject(), name, x, y, z, w);
|
||||
@@ -284,6 +295,7 @@ public class MaterialInstance {
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y, int z, int w) {
|
||||
nSetParameterInt4(getNativeObject(), name, x, y, z, w);
|
||||
@@ -299,6 +311,7 @@ public class MaterialInstance {
|
||||
* @param name The name of the material texture parameter
|
||||
* @param texture The texture to set as parameter
|
||||
* @param sampler The sampler to be used with this texture
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull Texture texture, @NonNull TextureSampler sampler) {
|
||||
@@ -320,6 +333,7 @@ public class MaterialInstance {
|
||||
* instance.setParameter("param", MaterialInstance.BooleanElement.BOOL4, a, 0, 4);
|
||||
* }</pre>
|
||||
* </p>
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull BooleanElement type, @NonNull boolean[] v,
|
||||
@@ -342,6 +356,7 @@ public class MaterialInstance {
|
||||
* instance.setParameter("param", MaterialInstance.IntElement.INT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* </p>
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull IntElement type, @NonNull int[] v,
|
||||
@@ -364,6 +379,7 @@ public class MaterialInstance {
|
||||
* material.setDefaultParameter("param", MaterialInstance.FloatElement.FLOAT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* </p>
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull FloatElement type, @NonNull float[] v,
|
||||
@@ -379,6 +395,7 @@ public class MaterialInstance {
|
||||
* @param r red component
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, @NonNull Colors.RgbType type,
|
||||
float r, float g, float b) {
|
||||
@@ -395,6 +412,7 @@ public class MaterialInstance {
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
* @param a alpha component
|
||||
* @throws RuntimeException if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
public void setParameter(@NonNull String name, @NonNull Colors.RgbaType type,
|
||||
float r, float g, float b, float a) {
|
||||
|
||||
+2
@@ -112,6 +112,8 @@ public class MorphTargetBuffer {
|
||||
* @return the newly created <code>MorphTargetBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the MorphTargetBuffer could not be created
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*
|
||||
* @see #setMorphTargetBufferOffsetAt
|
||||
*/
|
||||
|
||||
+1
@@ -587,6 +587,7 @@ public class RenderableManager {
|
||||
*
|
||||
* @param engine reference to the <code>Engine</code> to associate this renderable with
|
||||
* @param entity entity to add the renderable component to
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of memory or other resources, or if a parameter to a builder function was invalid.
|
||||
*/
|
||||
public void build(@NonNull Engine engine, @Entity int entity) {
|
||||
if (!nBuilderBuild(mNativeBuilder, engine.getNativeObject(), entity)) {
|
||||
|
||||
@@ -269,9 +269,8 @@ public class Renderer {
|
||||
|
||||
/**
|
||||
* Set the time at which the frame must be presented to the display.
|
||||
* <p>
|
||||
*
|
||||
* This must be called between {@link #beginFrame} and {@link #endFrame}.
|
||||
* </p>
|
||||
*
|
||||
* @param monotonicClockNanos The time in nanoseconds corresponding to the system monotonic
|
||||
* up-time clock. The presentation time is typically set in the
|
||||
@@ -354,6 +353,8 @@ public class Renderer {
|
||||
* returned and produce a frame anyways, by making calls to {@link #render(View)},
|
||||
* in which case {@link #endFrame} must be called.
|
||||
*
|
||||
* @throws Error if the backend thread encountered an unrecoverable error.
|
||||
*
|
||||
* @see #endFrame
|
||||
* @see #render
|
||||
*/
|
||||
@@ -370,6 +371,8 @@ public class Renderer {
|
||||
*
|
||||
* <br><p>All calls to render() must happen <b>before</b> endFrame().</p>
|
||||
*
|
||||
* @throws Error if the backend thread encountered an unrecoverable error, or if called again after a backend exception was already thrown.
|
||||
*
|
||||
* @see #beginFrame
|
||||
* @see #render
|
||||
*/
|
||||
@@ -425,6 +428,7 @@ public class Renderer {
|
||||
* </ul>
|
||||
*
|
||||
* @param view the {@link View} to render
|
||||
* @throws Error if the backend thread encountered an unrecoverable error, or if called again after a backend exception was already thrown.
|
||||
* @see #beginFrame
|
||||
* @see #endFrame
|
||||
* @see View
|
||||
@@ -454,6 +458,7 @@ public class Renderer {
|
||||
* <li><code>renderStandaloneView()</code> performs potentially heavy computations and cannot be
|
||||
* multi-threaded. However, internally, it is highly multi-threaded to both improve performance
|
||||
* and mitigate the call's latency.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param view the {@link View} to render. This View must have an associated {@link RenderTarget}
|
||||
* @see View
|
||||
@@ -519,14 +524,14 @@ public class Renderer {
|
||||
* <p><code>readPixels</code> must be called within a frame, meaning after {@link #beginFrame}
|
||||
* and before {@link #endFrame}. Typically, <code>readPixels</code> will be called after
|
||||
* {@link #render}.</p>
|
||||
* <br>
|
||||
* <p>After calling this method, the callback associated with <code>buffer</code>
|
||||
* will be invoked on the main thread, indicating that the read-back has completed.
|
||||
* Typically, this will happen after multiple calls to {@link #beginFrame},
|
||||
* {@link #render}, {@link #endFrame}.</p>
|
||||
* <br>
|
||||
* <p><code>readPixels</code> is intended for debugging and testing.
|
||||
* It will impact performance significantly.</p>
|
||||
*
|
||||
* <p>After issuing this method, the callback associated with <code>buffer</code> will be invoked on the
|
||||
* main thread, indicating that the read-back has completed. Typically, this will happen
|
||||
* after multiple calls to {@link #beginFrame}, {@link #render}, {@link #endFrame}.</p>
|
||||
*
|
||||
* <p>It is also possible to use a {@link Fence} to wait for the read-back.</p>
|
||||
*
|
||||
* <p><code>readPixels</code> is intended for debugging and testing. It will impact performance significantly.</p>
|
||||
*
|
||||
* @param xoffset left offset of the sub-region to read back
|
||||
* @param yoffset bottom offset of the sub-region to read back
|
||||
@@ -604,18 +609,19 @@ public class Renderer {
|
||||
*
|
||||
* <p>Typically <code>readPixels</code> will be called after {@link #render} and before
|
||||
* {@link #endFrame}.</p>
|
||||
* <br>
|
||||
* <p>After calling this method, the callback associated with <code>buffer</code>
|
||||
* will be invoked on the main thread, indicating that the read-back has completed.
|
||||
* Typically, this will happen after multiple calls to {@link #beginFrame},
|
||||
* {@link #render}, {@link #endFrame}.</p>
|
||||
* <br>
|
||||
*
|
||||
* <p>After issuing this method, the callback associated with <code>buffer</code> will be invoked on the
|
||||
* main thread, indicating that the read-back has completed. Typically, this will happen
|
||||
* after multiple calls to {@link #beginFrame}, {@link #render}, {@link #endFrame}.</p>
|
||||
*
|
||||
* <p>It is also possible to use a {@link Fence} to wait for the read-back.</p>
|
||||
*
|
||||
* <p>OpenGL only: if issuing a <code>readPixels</code> on a {@link RenderTarget} backed by a
|
||||
* {@link Texture} that had data uploaded to it via {@link Texture#setImage}, the data returned
|
||||
* from <code>readPixels</code> will be y-flipped with respect to the {@link Texture#setImage}
|
||||
* call.</p>
|
||||
* <p><code>readPixels</code> is intended for debugging and testing.
|
||||
* It will impact performance significantly.</p>
|
||||
*
|
||||
* <p><code>readPixels</code> is intended for debugging and testing. It will impact performance significantly.</p>
|
||||
*
|
||||
* @param renderTarget {@link RenderTarget} to read back from
|
||||
* @param xoffset left offset of the sub-region to read back
|
||||
|
||||
@@ -78,6 +78,8 @@ public class SkinningBuffer {
|
||||
* @return the newly created <code>SkinningBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the SkinningBuffer could not be created
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*
|
||||
* @see #setBonesAsMatrices
|
||||
* @see #setBonesAsQuaternions
|
||||
|
||||
@@ -885,6 +885,8 @@ public class Texture {
|
||||
* @return A newly created <code>Texture</code>
|
||||
* @exception IllegalStateException if a parameter to a builder function was invalid.
|
||||
* A mode detailed message about the error is output in the system log.
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*/
|
||||
@NonNull
|
||||
public Texture build(@NonNull Engine engine) {
|
||||
|
||||
@@ -272,6 +272,8 @@ public class VertexBuffer {
|
||||
* @return the newly created <code>VertexBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the VertexBuffer could not be created
|
||||
* @throws RuntimeException if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
*/
|
||||
@NonNull
|
||||
public VertexBuffer build(@NonNull Engine engine) {
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include <atomic>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -75,6 +77,25 @@ public:
|
||||
|
||||
bool isExitRequested() const;
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
bool hasUnrecoverableError() const noexcept {
|
||||
return mHasUnrecoverableError.load(std::memory_order_acquire);
|
||||
}
|
||||
void setUnrecoverableException(std::exception_ptr e) noexcept {
|
||||
mBackendException = e;
|
||||
mHasUnrecoverableError.store(true, std::memory_order_release);
|
||||
}
|
||||
void propagateBackendException() const;
|
||||
bool hasExceptionBeenRethrown() const noexcept {
|
||||
return mExceptionRethrown.load(std::memory_order_relaxed);
|
||||
}
|
||||
#else
|
||||
void propagateBackendException() const noexcept {}
|
||||
constexpr bool hasUnrecoverableError() const noexcept { return false; }
|
||||
constexpr bool hasExceptionBeenRethrown() const noexcept { return false; }
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
const size_t mRequiredSize;
|
||||
|
||||
@@ -91,6 +112,12 @@ private:
|
||||
bool mPaused = false;
|
||||
|
||||
static constexpr uint32_t EXIT_REQUESTED = 0x31415926;
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
mutable std::exception_ptr mBackendException;
|
||||
std::atomic<bool> mHasUnrecoverableError{false};
|
||||
mutable std::atomic<bool> mExceptionRethrown{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -75,6 +75,12 @@ public:
|
||||
// thread via `purge()`.
|
||||
virtual void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) = 0;
|
||||
|
||||
/**
|
||||
* Flags the driver as having encountered an unrecoverable error.
|
||||
* This will interrupt all pending fence waits and prevent further waits.
|
||||
*/
|
||||
virtual void setUnrecoverableError() noexcept {}
|
||||
|
||||
virtual ShaderModel getShaderModel() const noexcept = 0;
|
||||
|
||||
// The shader languages used for shaders for this driver in order of preference, used to inform
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -79,8 +80,28 @@ bool CommandBufferQueue::isExitRequested() const {
|
||||
}
|
||||
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
void CommandBufferQueue::propagateBackendException() const {
|
||||
if (UTILS_VERY_UNLIKELY(hasUnrecoverableError())) {
|
||||
if (!mExceptionRethrown.exchange(true, std::memory_order_relaxed)) {
|
||||
std::rethrow_exception(mBackendException);
|
||||
} else {
|
||||
FILAMENT_CHECK_POSTCONDITION(false)
|
||||
<< "Engine is in unrecoverable state due to previous backend exception";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CommandBufferQueue::flush() {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
#ifdef __EXCEPTIONS
|
||||
if (UTILS_VERY_UNLIKELY(hasUnrecoverableError())) {
|
||||
// Drop the current buffer to avoid filling up the circular buffer
|
||||
mCircularBuffer.getBuffer();
|
||||
propagateBackendException();
|
||||
}
|
||||
#endif
|
||||
|
||||
CircularBuffer& circularBuffer = mCircularBuffer;
|
||||
if (circularBuffer.empty()) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include "private/backend/Driver.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -214,18 +215,48 @@ public:
|
||||
|
||||
void scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) final;
|
||||
|
||||
/**
|
||||
* Waits for a predicate to become true or until a timeout is reached.
|
||||
* Returns ERROR if the driver encountered an unrecoverable error.
|
||||
*/
|
||||
template<typename Predicate>
|
||||
bool waitForFence(Predicate predicate, std::chrono::steady_clock::time_point until) {
|
||||
FenceStatus waitForFence(Predicate predicate, std::chrono::steady_clock::time_point until) {
|
||||
std::unique_lock lock(mFenceMutex);
|
||||
return mFenceCondition.wait_until(lock, until, predicate);
|
||||
bool errorObserved = false;
|
||||
bool success = mFenceCondition.wait_until(lock, until, [&]() {
|
||||
return predicate() ||
|
||||
(errorObserved = UTILS_VERY_UNLIKELY(mHasUnrecoverableError.load(std::memory_order_relaxed)));
|
||||
});
|
||||
|
||||
if (UTILS_VERY_UNLIKELY(errorObserved)) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
|
||||
return success ? FenceStatus::CONDITION_SATISFIED : FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a predicate to become true indefinitely.
|
||||
* Returns ERROR if the driver encountered an unrecoverable error.
|
||||
*/
|
||||
template<typename Predicate>
|
||||
void waitForFence(Predicate predicate) {
|
||||
FenceStatus waitForFence(Predicate predicate) {
|
||||
std::unique_lock lock(mFenceMutex);
|
||||
mFenceCondition.wait(lock, predicate);
|
||||
bool errorObserved = false;
|
||||
mFenceCondition.wait(lock, [&]() {
|
||||
return predicate() ||
|
||||
(errorObserved = UTILS_VERY_UNLIKELY(mHasUnrecoverableError.load(std::memory_order_relaxed)));
|
||||
});
|
||||
|
||||
if (UTILS_VERY_UNLIKELY(errorObserved)) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an action that signals a fence and notifies all waiters.
|
||||
*/
|
||||
template<typename Action>
|
||||
void signalFence(Action action) {
|
||||
std::lock_guard lock(mFenceMutex);
|
||||
@@ -233,6 +264,22 @@ public:
|
||||
mFenceCondition.notify_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags the driver as having encountered an unrecoverable error.
|
||||
*/
|
||||
void setUnrecoverableError() noexcept override {
|
||||
std::lock_guard lock(mFenceMutex);
|
||||
mHasUnrecoverableError.store(true, std::memory_order_relaxed);
|
||||
mFenceCondition.notify_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the driver has encountered an unrecoverable error.
|
||||
*/
|
||||
bool hasUnrecoverableError() const noexcept {
|
||||
return mHasUnrecoverableError.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Privates
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@@ -275,6 +322,7 @@ private:
|
||||
|
||||
std::condition_variable mFenceCondition;
|
||||
std::mutex mFenceMutex;
|
||||
std::atomic<bool> mHasUnrecoverableError{false};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
ShaderLanguage preferredLanguage) const noexcept final;
|
||||
|
||||
// Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block.
|
||||
void execute(std::function<void(void)> const& fn) noexcept final;
|
||||
void execute(std::function<void(void)> const& fn) final;
|
||||
|
||||
/*
|
||||
* Tasks run regularly on the driver thread.
|
||||
|
||||
@@ -307,7 +307,7 @@ void MetalDriver::setFrameCompletedCallback(
|
||||
swapChain->setFrameCompletedCallback(handler, std::move(callback));
|
||||
}
|
||||
|
||||
void MetalDriver::execute(std::function<void(void)> const& fn) noexcept {
|
||||
void MetalDriver::execute(std::function<void(void)> const& fn) {
|
||||
@autoreleasepool {
|
||||
fn();
|
||||
}
|
||||
|
||||
@@ -1428,11 +1428,17 @@ FenceStatus MetalFence::wait(uint64_t timeoutNs) {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
FenceStatus status;
|
||||
if (timeoutNs == FENCE_WAIT_FOR_EVER) {
|
||||
context.driver->waitForFence(predicate);
|
||||
status = context.driver->waitForFence(predicate);
|
||||
} else {
|
||||
auto const until = std::chrono::steady_clock::now() + ns(timeoutNs);
|
||||
context.driver->waitForFence(predicate, until);
|
||||
status = context.driver->waitForFence(predicate, until);
|
||||
}
|
||||
|
||||
if (status == FenceStatus::ERROR) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2665,12 +2665,17 @@ FenceStatus OpenGLDriver::fenceWait(FenceHandle fh, uint64_t const timeout) {
|
||||
// so we need to wait for that, before using the real fence.
|
||||
// By construction, "f" can't be destroyed while we wait, because its
|
||||
// construction call is in the queue and a destroy call will have to come later.
|
||||
waitForFence([f] {
|
||||
FenceStatus status = waitForFence([f] {
|
||||
return f->fence != nullptr;
|
||||
}, until);
|
||||
|
||||
if (status == FenceStatus::ERROR) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
|
||||
if (f->fence == nullptr) {
|
||||
// the only possible choice here is that we timed out
|
||||
assert_invariant(f->state->status == FenceStatus::TIMEOUT_EXPIRED);
|
||||
assert_invariant(status == FenceStatus::TIMEOUT_EXPIRED);
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
// here we know that we have the platform fence
|
||||
@@ -2686,13 +2691,17 @@ FenceStatus OpenGLDriver::fenceWait(FenceHandle fh, uint64_t const timeout) {
|
||||
// This is the case where we need to use OpenGL fences
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
FenceStatus result = FenceStatus::TIMEOUT_EXPIRED;
|
||||
waitForFence([&] {
|
||||
FenceStatus status = waitForFence([&] {
|
||||
if (f->state->status != FenceStatus::TIMEOUT_EXPIRED) {
|
||||
result = f->state->status;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, until);
|
||||
|
||||
if (status == FenceStatus::ERROR) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return FenceStatus::ERROR;
|
||||
|
||||
@@ -1492,16 +1492,20 @@ FenceStatus VulkanDriver::fenceWait(FenceHandle const fh, uint64_t const timeout
|
||||
|
||||
std::shared_ptr<VulkanCmdFence> cmdfence;
|
||||
bool canceled = false;
|
||||
waitForFence([&] {
|
||||
auto status = fence->getStatus();
|
||||
if (bool(status.first) || status.second) {
|
||||
cmdfence = status.first;
|
||||
canceled = status.second;
|
||||
FenceStatus status = waitForFence([&] {
|
||||
auto fstatus = fence->getStatus();
|
||||
if (bool(fstatus.first) || fstatus.second) {
|
||||
cmdfence = fstatus.first;
|
||||
canceled = fstatus.second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, until);
|
||||
|
||||
if (status == FenceStatus::ERROR) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
|
||||
if (!cmdfence || canceled) {
|
||||
return canceled ? FenceStatus::ERROR : FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
|
||||
@@ -796,12 +796,16 @@ FenceStatus WebGPUDriver::fenceWait(FenceHandle fenceHandle, uint64_t const time
|
||||
}
|
||||
|
||||
std::shared_ptr<WebGPUSubmissionState> state;
|
||||
bool const success = waitForFence([&] {
|
||||
FenceStatus status = waitForFence([&] {
|
||||
state = fence->getState();
|
||||
return bool(state);
|
||||
}, until);
|
||||
|
||||
if (!success) {
|
||||
if (status == FenceStatus::ERROR) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
|
||||
if (status == FenceStatus::TIMEOUT_EXPIRED) {
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "Skip.h"
|
||||
#include "../src/DriverBase.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
@@ -140,4 +141,32 @@ TEST_F(BackendTest, FrameCompletedCallback) {
|
||||
EXPECT_EQ(callbackCountB, 1);
|
||||
}
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
TEST_F(BackendTest, FenceUnrecoverableErrorInterruption) {
|
||||
DriverBase* driverBase = static_cast<DriverBase*>(&getDriver());
|
||||
|
||||
std::atomic<bool> waitStarted = false;
|
||||
std::atomic<bool> waitFinished = false;
|
||||
FenceStatus waitResult = FenceStatus::TIMEOUT_EXPIRED;
|
||||
|
||||
std::thread waitingThread([&]() {
|
||||
waitStarted = true;
|
||||
waitResult = driverBase->waitForFence([]() { return false; });
|
||||
waitFinished = true;
|
||||
});
|
||||
|
||||
while (!waitStarted) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
driverBase->setUnrecoverableError();
|
||||
|
||||
waitingThread.join();
|
||||
|
||||
EXPECT_TRUE(waitFinished);
|
||||
EXPECT_EQ(waitResult, FenceStatus::ERROR);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -303,4 +303,37 @@ TEST_F(CommandBufferQueueTest, StressTest) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
TEST_F(CommandBufferQueueTest, BackendExceptionHandling) {
|
||||
CommandBufferQueue queue(1024, 4096, false);
|
||||
|
||||
// Simulate an exception in the backend thread
|
||||
std::thread backend([&]() {
|
||||
try {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
throw std::runtime_error("Artificial Backend Failure");
|
||||
} catch (...) {
|
||||
queue.setUnrecoverableException(std::current_exception());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Wait for backend to fail
|
||||
std::this_thread::sleep_for(50ms);
|
||||
|
||||
// First call to flush should throw the original exception
|
||||
EXPECT_THROW({
|
||||
queue.flush();
|
||||
}, std::runtime_error);
|
||||
|
||||
// Subsequent calls should throw due to postcondition check
|
||||
EXPECT_THROW({
|
||||
queue.flush();
|
||||
}, utils::Panic);
|
||||
|
||||
backend.join();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ public:
|
||||
* @param near distance in world units from the camera to the near plane.
|
||||
* @param far distance in world units from the camera to the far plane. \p far != \p near.
|
||||
*/
|
||||
void setCustomProjection(math::mat4 const& projection, double near, double far) noexcept;
|
||||
void setCustomProjection(math::mat4 const& projection, double near, double far);
|
||||
|
||||
/** Sets the projection matrix.
|
||||
*
|
||||
@@ -286,7 +286,7 @@ public:
|
||||
* @param far distance in world units from the camera to the far plane. \p far != \p near.
|
||||
*/
|
||||
void setCustomProjection(math::mat4 const& projection, math::mat4 const& projectionForCulling,
|
||||
double near, double far) noexcept;
|
||||
double near, double far);
|
||||
|
||||
/** Sets a custom projection matrix for each eye.
|
||||
*
|
||||
|
||||
@@ -782,6 +782,17 @@ public:
|
||||
*/
|
||||
bool isAsynchronousModeEnabled() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether the engine has encountered an unrecoverable failure.
|
||||
*
|
||||
* If this returns true, the engine is in an unrecoverable state and further calls to
|
||||
* rendering methods will fail or be ignored. Apps can use this to check for fatal
|
||||
* errors instead of relying on exceptions.
|
||||
*
|
||||
* @return true if an unrecoverable failure has occurred, false otherwise.
|
||||
*/
|
||||
bool hasUnrecoverableFailure() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieves the configuration settings of this Engine.
|
||||
*
|
||||
@@ -1099,6 +1110,8 @@ public:
|
||||
* in cases where a guarantee about the <code>SwapChain</code> destruction is needed in a
|
||||
* timely fashion, such as when responding to Android's
|
||||
* <code>android.view.SurfaceHolder.Callback.surfaceDestroyed</code></p>
|
||||
*
|
||||
* @note If the backend thread has encountered an unrecoverable error, this function becomes a no-op.
|
||||
*/
|
||||
void flushAndWait();
|
||||
|
||||
@@ -1118,6 +1131,8 @@ public:
|
||||
* @param timeout A timeout in nanoseconds
|
||||
* @return true if successful, false if flushAndWait timed out, in which case it wasn't successful and commands
|
||||
* might still be executing on both the CPU and GPU sides.
|
||||
*
|
||||
* @note If the backend thread has encountered an unrecoverable error, this function becomes a no-op and returns false.
|
||||
*/
|
||||
bool flushAndWait(uint64_t timeout);
|
||||
|
||||
@@ -1127,7 +1142,9 @@ public:
|
||||
*
|
||||
* <p>This is typically used after creating a lot of objects to start draining the command
|
||||
* queue which has a limited size.</p>
|
||||
*/
|
||||
*
|
||||
* @note If the backend thread has encountered an unrecoverable error, this function becomes a no-op.
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,6 +62,9 @@ public:
|
||||
* @return FenceStatus::CONDITION_SATISFIED on success,
|
||||
* FenceStatus::TIMEOUT_EXPIRED if the time out expired or
|
||||
* FenceStatus::ERROR in other cases.
|
||||
* @throws std::exception (or derived) if the backend thread encountered an unrecoverable error (when exceptions are enabled and mode is Mode::FLUSH).
|
||||
* @throws utils::Panic if called again after a backend exception was already thrown.
|
||||
*
|
||||
* @see #Mode
|
||||
*/
|
||||
FenceStatus wait(Mode mode = Mode::FLUSH, uint64_t timeout = FENCE_WAIT_FOR_EVER);
|
||||
|
||||
@@ -298,9 +298,11 @@ public:
|
||||
* This is a convenience method that returns the same value as beginFrame().
|
||||
*
|
||||
* @return
|
||||
* *false* the current frame should be skipped,
|
||||
* *false* the current frame should be skipped, or an unrecoverable backend exception has occurred.
|
||||
* *true* the current frame can be rendered
|
||||
*
|
||||
* @note This method will return false once a backend exception has been delivered to the main thread.
|
||||
*
|
||||
* @see
|
||||
* beginFrame()
|
||||
*/
|
||||
@@ -344,6 +346,10 @@ public:
|
||||
* It is recommended to use the same swapChain for every call to beginFrame, failing to do
|
||||
* so can result is losing all or part of the FrameInfo history.
|
||||
*
|
||||
* @throws std::exception (or derived) if the backend thread encountered an unrecoverable error (when exceptions are enabled).
|
||||
*
|
||||
* @note This method will return false if called again after a backend exception was already thrown and delivered to the main thread.
|
||||
*
|
||||
* @see
|
||||
* endFrame()
|
||||
*/
|
||||
@@ -414,6 +420,9 @@ public:
|
||||
* @remark
|
||||
* render() is typically called once per frame (but not necessarily).
|
||||
*
|
||||
* @throws std::exception (or derived) if the backend thread encountered an unrecoverable error (when exceptions are enabled).
|
||||
* @throws utils::Panic if called again after a backend exception was already thrown.
|
||||
*
|
||||
* @see
|
||||
* beginFrame(), endFrame(), View
|
||||
*
|
||||
@@ -506,6 +515,9 @@ public:
|
||||
* beginFrame() returned true, otherwise, endFrame() must not be called unless the caller
|
||||
* ignored beginFrame()'s return value.
|
||||
*
|
||||
* @throws std::exception (or derived) if the backend thread encountered an unrecoverable error (when exceptions are enabled).
|
||||
* @throws utils::Panic if called again after a backend exception was already thrown.
|
||||
*
|
||||
* @see
|
||||
* beginFrame()
|
||||
*/
|
||||
|
||||
@@ -567,7 +567,7 @@ public:
|
||||
* @see PlatformCocoaGL::createExternalImage
|
||||
* @see PlatformCocoaTouchGL::createExternalImage
|
||||
*/
|
||||
void setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept;
|
||||
void setExternalImage(Engine& engine, ExternalImageHandleRef image);
|
||||
|
||||
/**
|
||||
* Specify the external image to associate with this Texture. Typically, the external
|
||||
@@ -594,7 +594,7 @@ public:
|
||||
* @deprecated Instead, use setExternalImage(Engine& engine, ExternalImageHandleRef image)
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept;
|
||||
void setExternalImage(Engine& engine, void* UTILS_NONNULL image);
|
||||
|
||||
/**
|
||||
* Specify the external image and plane to associate with this Texture. Typically, the external
|
||||
@@ -625,7 +625,7 @@ public:
|
||||
* kCVPixelFormatType_420YpCbCr8BiPlanarFullRange images. On platforms
|
||||
* other than iOS, this method is a no-op.
|
||||
*/
|
||||
void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane) noexcept;
|
||||
void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane);
|
||||
|
||||
/**
|
||||
* Specify the external stream to associate with this Texture. Typically, the external
|
||||
@@ -644,7 +644,7 @@ public:
|
||||
* @see Builder::sampler(), Stream
|
||||
*
|
||||
*/
|
||||
void setExternalStream(Engine& engine, Stream* UTILS_NULLABLE stream) noexcept;
|
||||
void setExternalStream(Engine& engine, Stream* UTILS_NULLABLE stream);
|
||||
|
||||
/**
|
||||
* Generates all the mipmap levels automatically. This requires the texture to have a
|
||||
@@ -656,7 +656,7 @@ public:
|
||||
* @attention \p engine must be the instance passed to Builder::build()
|
||||
* @attention This Texture instance must NOT use SamplerType::SAMPLER_3D or it has no effect
|
||||
*/
|
||||
void generateMipmaps(Engine& engine) const noexcept;
|
||||
void generateMipmaps(Engine& engine) const;
|
||||
|
||||
/**
|
||||
* This non-blocking method checks if the resource has finished creation. If the resource
|
||||
|
||||
@@ -464,7 +464,7 @@ public:
|
||||
/**
|
||||
* Enables or disables bloom in the post-processing stage. Disabled by default.
|
||||
*
|
||||
* @param options options
|
||||
* @param options options. Values may be silently clamped to valid ranges.
|
||||
*/
|
||||
void setBloomOptions(BloomOptions options) noexcept;
|
||||
|
||||
|
||||
@@ -81,12 +81,12 @@ void Camera::setProjection(Projection const projection, double const left, doubl
|
||||
downcast(this)->setProjection(projection, left, right, bottom, top, near, far);
|
||||
}
|
||||
|
||||
void Camera::setCustomProjection(mat4 const& projection, double const near, double const far) noexcept {
|
||||
void Camera::setCustomProjection(mat4 const& projection, double const near, double const far) {
|
||||
downcast(this)->setCustomProjection(projection, near, far);
|
||||
}
|
||||
|
||||
void Camera::setCustomProjection(mat4 const& projection, mat4 const& projectionForCulling,
|
||||
double const near, double const far) noexcept {
|
||||
double const near, double const far) {
|
||||
downcast(this)->setCustomProjection(projection, projectionForCulling, near, far);
|
||||
}
|
||||
|
||||
|
||||
@@ -474,6 +474,10 @@ bool Engine::isAsynchronousModeEnabled() const noexcept {
|
||||
return downcast(this)->isAsynchronousModeEnabled();
|
||||
}
|
||||
|
||||
bool Engine::hasUnrecoverableFailure() const noexcept {
|
||||
return downcast(this)->hasUnrecoverableFailure();
|
||||
}
|
||||
|
||||
size_t Engine::getMaxStereoscopicEyes() noexcept {
|
||||
return FEngine::getMaxStereoscopicEyes();
|
||||
}
|
||||
|
||||
@@ -68,23 +68,23 @@ backend::AsyncCallId Texture::setImageAsync(Engine& engine, size_t const level,
|
||||
handler, std::move(callback), user);
|
||||
}
|
||||
|
||||
void Texture::setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept {
|
||||
void Texture::setExternalImage(Engine& engine, ExternalImageHandleRef image) {
|
||||
downcast(this)->setExternalImage(downcast(engine), image);
|
||||
}
|
||||
|
||||
void Texture::setExternalImage(Engine& engine, void* image) noexcept {
|
||||
void Texture::setExternalImage(Engine& engine, void* image) {
|
||||
downcast(this)->setExternalImage(downcast(engine), image);
|
||||
}
|
||||
|
||||
void Texture::setExternalImage(Engine& engine, void* image, size_t const plane) noexcept {
|
||||
void Texture::setExternalImage(Engine& engine, void* image, size_t const plane) {
|
||||
downcast(this)->setExternalImage(downcast(engine), image, plane);
|
||||
}
|
||||
|
||||
void Texture::setExternalStream(Engine& engine, Stream* stream) noexcept {
|
||||
void Texture::setExternalStream(Engine& engine, Stream* stream) {
|
||||
downcast(this)->setExternalStream(downcast(engine), downcast(stream));
|
||||
}
|
||||
|
||||
void Texture::generateMipmaps(Engine& engine) const noexcept {
|
||||
void Texture::generateMipmaps(Engine& engine) const {
|
||||
downcast(this)->generateMipmaps(downcast(engine));
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ mat4 FCamera::projection(double const focalLengthInMillimeters,
|
||||
*/
|
||||
|
||||
void UTILS_NOINLINE FCamera::setCustomProjection(mat4 const& projection,
|
||||
mat4 const& projectionForCulling, double const near, double const far) noexcept {
|
||||
mat4 const& projectionForCulling, double const near, double const far) {
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(near != far)
|
||||
<< "Camera preconditions not met in setCustomProjection(): near = far = " << near;
|
||||
|
||||
@@ -53,10 +53,10 @@ public:
|
||||
|
||||
// Sets custom projection matrices (sets both the viewing and culling projections).
|
||||
void setCustomProjection(math::mat4 const& projection,
|
||||
math::mat4 const& projectionForCulling, double near, double far) noexcept;
|
||||
math::mat4 const& projectionForCulling, double near, double far);
|
||||
|
||||
inline void setCustomProjection(math::mat4 const& projection,
|
||||
double const near, double const far) noexcept {
|
||||
double const near, double const far) {
|
||||
setCustomProjection(projection, projection, near, far);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,10 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
#include <exception>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -831,6 +835,11 @@ void FEngine::submitFrame() {
|
||||
}
|
||||
|
||||
void FEngine::flush() {
|
||||
if (UTILS_VERY_UNLIKELY(mCommandBufferQueue.hasUnrecoverableError())) {
|
||||
return;
|
||||
}
|
||||
propagateBackendException();
|
||||
|
||||
// flush the command buffer
|
||||
flushCommandBuffer(mCommandBufferQueue);
|
||||
|
||||
@@ -846,6 +855,11 @@ void FEngine::flushAndWait() {
|
||||
}
|
||||
|
||||
bool FEngine::flushAndWait(uint64_t const timeout) {
|
||||
if (UTILS_VERY_UNLIKELY(mCommandBufferQueue.hasUnrecoverableError())) {
|
||||
return false;
|
||||
}
|
||||
propagateBackendException();
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
|
||||
<< "Cannot call Engine::flushAndWait() when rendering thread is paused!";
|
||||
|
||||
@@ -954,8 +968,10 @@ int FEngine::loop() {
|
||||
}
|
||||
|
||||
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
|
||||
getDriver().purge();
|
||||
commandBufferQueue.flush();
|
||||
if (!commandBufferQueue.hasUnrecoverableError()) {
|
||||
getDriver().purge();
|
||||
commandBufferQueue.flush();
|
||||
}
|
||||
}
|
||||
|
||||
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
||||
@@ -1594,15 +1610,39 @@ bool FEngine::execute() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// execute all command buffers
|
||||
auto& driver = getDriverApi();
|
||||
for (auto& item : buffers) {
|
||||
if (UTILS_LIKELY(item.begin)) {
|
||||
driver.execute(item.begin);
|
||||
if (UTILS_VERY_UNLIKELY(mCommandBufferQueue.hasUnrecoverableError())) {
|
||||
for (auto& item : buffers) {
|
||||
mCommandBufferQueue.releaseBuffer(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// execute all command buffers
|
||||
auto& driver = getDriverApi();
|
||||
size_t i = 0;
|
||||
#ifdef __EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
for (; i < buffers.size(); ++i) {
|
||||
auto& item = buffers[i];
|
||||
if (UTILS_LIKELY(item.begin)) {
|
||||
driver.execute(item.begin);
|
||||
mCommandBufferQueue.releaseBuffer(item);
|
||||
}
|
||||
}
|
||||
#ifdef __EXCEPTIONS
|
||||
} catch (...) {
|
||||
mCommandBufferQueue.setUnrecoverableException(std::current_exception());
|
||||
mDriver->setUnrecoverableError();
|
||||
setFenceUnrecoverableError();
|
||||
// Release remaining buffers (including the one that failed)
|
||||
for (; i < buffers.size(); ++i) {
|
||||
mCommandBufferQueue.releaseBuffer(buffers[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1621,6 +1661,40 @@ void FEngine::setPaused(bool const paused) {
|
||||
mCommandBufferQueue.setPaused(paused);
|
||||
}
|
||||
|
||||
void FEngine::setFenceUnrecoverableError() noexcept {
|
||||
std::lock_guard const lock(mFenceLock);
|
||||
mFenceHasUnrecoverableError = true;
|
||||
mFenceCondition.notify_all();
|
||||
}
|
||||
|
||||
void FEngine::signalFence(FenceSignal& signal, FenceSignal::State s) noexcept {
|
||||
std::lock_guard const lock(mFenceLock);
|
||||
signal.mState = s;
|
||||
mFenceCondition.notify_all();
|
||||
}
|
||||
|
||||
Fence::FenceStatus FEngine::waitFence(FenceSignal& signal, uint64_t const timeout) noexcept {
|
||||
std::unique_lock lock(mFenceLock);
|
||||
while (signal.mState == FenceSignal::UNSIGNALED && !mFenceHasUnrecoverableError) {
|
||||
if (timeout == FENCE_WAIT_FOR_EVER) {
|
||||
mFenceCondition.wait(lock);
|
||||
} else {
|
||||
if (timeout == 0 ||
|
||||
mFenceCondition.wait_for(lock, std::chrono::nanoseconds(timeout)) == std::cv_status::timeout) {
|
||||
if (mFenceHasUnrecoverableError) break;
|
||||
return Fence::FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UTILS_VERY_UNLIKELY(mFenceHasUnrecoverableError)) {
|
||||
return Fence::FenceStatus::ERROR;
|
||||
}
|
||||
if (signal.mState == FenceSignal::DESTROYED) {
|
||||
return Fence::FenceStatus::ERROR;
|
||||
}
|
||||
return Fence::FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept {
|
||||
DriverApi& driver = const_cast<FEngine*>(this)->getDriverApi();
|
||||
return driver.getFeatureLevel();
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include <string_view>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -138,6 +139,22 @@ public:
|
||||
using Epoch = clock::time_point;
|
||||
using duration = clock::duration;
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
void propagateBackendException() const {
|
||||
mCommandBufferQueue.propagateBackendException();
|
||||
}
|
||||
#else
|
||||
void propagateBackendException() const noexcept {}
|
||||
#endif
|
||||
|
||||
bool hasExceptionBeenRethrown() const noexcept {
|
||||
return mCommandBufferQueue.hasExceptionBeenRethrown();
|
||||
}
|
||||
|
||||
bool hasUnrecoverableFailure() const noexcept {
|
||||
return mCommandBufferQueue.hasUnrecoverableError();
|
||||
}
|
||||
|
||||
public:
|
||||
static Engine* create(Builder const& builder);
|
||||
|
||||
@@ -197,6 +214,15 @@ public:
|
||||
return mActiveFeatureLevel;
|
||||
}
|
||||
|
||||
// Sets the fence unrecoverable error state and notifies all waiters.
|
||||
void setFenceUnrecoverableError() noexcept;
|
||||
|
||||
// Signals a fence and notifies all waiters.
|
||||
void signalFence(FenceSignal& signal, FenceSignal::State s) noexcept;
|
||||
|
||||
// Waits for a fence to be signaled or for a timeout.
|
||||
Fence::FenceStatus waitFence(FenceSignal& signal, uint64_t timeout) noexcept;
|
||||
|
||||
size_t getMaxAutomaticInstances() const noexcept {
|
||||
return CONFIG_MAX_INSTANCES;
|
||||
}
|
||||
@@ -656,6 +682,10 @@ private:
|
||||
utils::Mutex mFenceListLock;
|
||||
ResourceList<FFence> mFences{"Fence"};
|
||||
|
||||
mutable utils::Mutex mFenceLock;
|
||||
mutable utils::Condition mFenceCondition;
|
||||
bool mFenceHasUnrecoverableError = false;
|
||||
|
||||
// the sync list is accessed from multiple threads, because they are
|
||||
// synchronization objects.
|
||||
utils::Mutex mSyncListLock;
|
||||
|
||||
@@ -37,8 +37,6 @@ namespace filament {
|
||||
|
||||
using namespace backend;
|
||||
|
||||
utils::Mutex FFence::sLock;
|
||||
utils::Condition FFence::sCondition;
|
||||
|
||||
static constexpr uint64_t PUMP_INTERVAL_MILLISECONDS = 1;
|
||||
|
||||
@@ -51,14 +49,15 @@ FFence::FFence(FEngine& engine)
|
||||
|
||||
// we have to first wait for the fence to be signaled by the command stream
|
||||
auto& fs = mFenceSignal;
|
||||
driverApi.queueCommand([fs]() {
|
||||
fs->signal();
|
||||
FEngine* const pEngine = &engine;
|
||||
driverApi.queueCommand([fs, pEngine]() {
|
||||
pEngine->signalFence(*fs, FenceSignal::SIGNALED);
|
||||
});
|
||||
}
|
||||
|
||||
void FFence::terminate(FEngine&) noexcept {
|
||||
void FFence::terminate(FEngine& engine) noexcept {
|
||||
FenceSignal * const fs = mFenceSignal.get();
|
||||
fs->signal(FenceSignal::DESTROYED);
|
||||
engine.signalFence(*fs, FenceSignal::DESTROYED);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
@@ -85,14 +84,14 @@ FenceStatus FFence::wait(Mode const mode, uint64_t const timeout) {
|
||||
FenceStatus status;
|
||||
|
||||
if (UTILS_LIKELY(!engine.pumpPlatformEvents())) {
|
||||
status = fs->wait(timeout);
|
||||
status = engine.waitFence(*fs, timeout);
|
||||
} else {
|
||||
// Unfortunately, some platforms might force us to have sync points between the GL thread
|
||||
// and user thread. To prevent deadlock on these platforms, we chop up the waiting time into
|
||||
// polling and pumping the platform's event queue.
|
||||
const auto startTime = std::chrono::system_clock::now();
|
||||
while (true) {
|
||||
status = fs->wait(ns(ms(PUMP_INTERVAL_MILLISECONDS)).count());
|
||||
status = engine.waitFence(*fs, ns(ms(PUMP_INTERVAL_MILLISECONDS)).count());
|
||||
if (status != FenceStatus::TIMEOUT_EXPIRED) {
|
||||
break;
|
||||
}
|
||||
@@ -111,30 +110,6 @@ FenceStatus FFence::wait(Mode const mode, uint64_t const timeout) {
|
||||
return status;
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void FFence::FenceSignal::signal(State const s) noexcept {
|
||||
std::lock_guard const lock(sLock);
|
||||
mState = s;
|
||||
sCondition.notify_all();
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
Fence::FenceStatus FFence::FenceSignal::wait(uint64_t const timeout) noexcept {
|
||||
std::unique_lock lock(sLock);
|
||||
while (mState == UNSIGNALED) {
|
||||
if (timeout == FENCE_WAIT_FOR_EVER) {
|
||||
sCondition.wait(lock);
|
||||
} else {
|
||||
if (timeout == 0 ||
|
||||
sCondition.wait_for(lock, ns(timeout)) == std::cv_status::timeout) {
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mState == DESTROYED) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -31,6 +31,11 @@ namespace filament {
|
||||
|
||||
class FEngine;
|
||||
|
||||
struct FenceSignal {
|
||||
enum State : uint8_t { UNSIGNALED, SIGNALED, DESTROYED };
|
||||
State mState = UNSIGNALED;
|
||||
};
|
||||
|
||||
class FFence : public Fence {
|
||||
public:
|
||||
FFence(FEngine& engine);
|
||||
@@ -42,19 +47,6 @@ public:
|
||||
static FenceStatus waitAndDestroy(FFence* fence, Mode mode) noexcept;
|
||||
|
||||
private:
|
||||
// We assume we don't have a lot of contention of fence and have all of them
|
||||
// share a single lock/condition
|
||||
static utils::Mutex sLock;
|
||||
static utils::Condition sCondition;
|
||||
|
||||
struct FenceSignal {
|
||||
explicit FenceSignal() noexcept = default;
|
||||
enum State : uint8_t { UNSIGNALED, SIGNALED, DESTROYED };
|
||||
State mState = UNSIGNALED;
|
||||
void signal(State s = SIGNALED) noexcept;
|
||||
FenceStatus wait(uint64_t timeout) noexcept;
|
||||
};
|
||||
|
||||
FEngine& mEngine;
|
||||
// TODO: use custom allocator for these small objects
|
||||
std::shared_ptr<FenceSignal> mFenceSignal;
|
||||
|
||||
@@ -117,7 +117,7 @@ void FInstanceBuffer::setLocalTransforms(
|
||||
memcpy(mLocalTransforms.data() + offset, localTransforms, sizeof(math::mat4f) * count);
|
||||
}
|
||||
|
||||
math::mat4f const& FInstanceBuffer::getLocalTransform(size_t index) const noexcept {
|
||||
math::mat4f const& FInstanceBuffer::getLocalTransform(size_t index) const {
|
||||
FILAMENT_CHECK_PRECONDITION(index < mInstanceCount)
|
||||
<< "getLocalTransform overflow: 'index (" << index
|
||||
<< ") must be < getInstanceCount() ("<< mInstanceCount << ").";
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
|
||||
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset);
|
||||
|
||||
math::mat4f const& getLocalTransform(size_t index) const noexcept;
|
||||
math::mat4f const& getLocalTransform(size_t index) const;
|
||||
|
||||
void prepare(
|
||||
PerRenderableData* buffer, uint32_t index, uint32_t count,
|
||||
|
||||
@@ -216,6 +216,24 @@ void FMaterialInstance::commit(FEngine& engine) const {
|
||||
}
|
||||
|
||||
void FMaterialInstance::commit(FEngine::DriverApi& driver, UboManager* uboManager) const {
|
||||
if (!mTextureParameters.empty()) {
|
||||
FEngine const& engine = mMaterial->getEngine();
|
||||
// First pass: check preconditions
|
||||
for (auto const& [binding, p]: mTextureParameters) {
|
||||
assert_invariant(p.texture);
|
||||
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
|
||||
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
|
||||
}
|
||||
// Second pass: update state
|
||||
for (auto const& [binding, p]: mTextureParameters) {
|
||||
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
|
||||
assert_invariant(handle);
|
||||
mDescriptorSet.setSampler(mMaterial->getDescriptorSetLayout(),
|
||||
binding, handle, p.params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mUniforms.isDirty()) {
|
||||
mUniforms.clean();
|
||||
if (isUsingUboBatching()) {
|
||||
@@ -232,19 +250,6 @@ void FMaterialInstance::commit(FEngine::DriverApi& driver, UboManager* uboManage
|
||||
driver.updateBufferObject(*ubHandle, mUniforms.toBufferDescriptor(driver), 0);
|
||||
}
|
||||
}
|
||||
if (!mTextureParameters.empty()) {
|
||||
for (auto const& [binding, p]: mTextureParameters) {
|
||||
assert_invariant(p.texture);
|
||||
// TODO: figure out a way to do this more efficiently (isValid() is a hashmap lookup)
|
||||
FEngine const& engine = mMaterial->getEngine();
|
||||
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
|
||||
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
|
||||
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
|
||||
assert_invariant(handle);
|
||||
mDescriptorSet.setSampler(mMaterial->getDescriptorSetLayout(),
|
||||
binding, handle, p.params);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: eventually we should remove this in RELEASE builds
|
||||
fixMissingSamplers();
|
||||
|
||||
@@ -316,6 +316,9 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
|
||||
}
|
||||
|
||||
bool FRenderer::shouldRenderFrame() const noexcept {
|
||||
if (UTILS_VERY_UNLIKELY(mEngine.hasExceptionBeenRethrown())) {
|
||||
return false;
|
||||
}
|
||||
FEngine& engine = mEngine;
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
bool const renderFrame = mFrameSkipper.shouldRenderFrame(driver);
|
||||
@@ -365,10 +368,16 @@ bool FRenderer::shouldRenderFrame() const noexcept {
|
||||
}
|
||||
|
||||
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
|
||||
assert_invariant(swapChain);
|
||||
FILAMENT_CHECK_PRECONDITION(swapChain) << "swapChain cannot be null.";
|
||||
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT, "frameId", (mFrameId + 1));
|
||||
|
||||
if (UTILS_VERY_UNLIKELY(mEngine.hasExceptionBeenRethrown())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mEngine.propagateBackendException();
|
||||
|
||||
if (!vsyncSteadyClockTimeNano) {
|
||||
vsyncSteadyClockTimeNano = mVsyncSteadyClockTimeNano;
|
||||
mVsyncSteadyClockTimeNano = 0;
|
||||
@@ -469,6 +478,8 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
void FRenderer::endFrame() {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
mEngine.propagateBackendException();
|
||||
|
||||
if (UTILS_UNLIKELY(mBeginFrameInternal)) {
|
||||
mBeginFrameInternal();
|
||||
mBeginFrameInternal = {};
|
||||
@@ -637,6 +648,8 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
void FRenderer::render(FView const* view) {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
mEngine.propagateBackendException();
|
||||
|
||||
if (UTILS_UNLIKELY(mBeginFrameInternal)) {
|
||||
// This is unlikely to happen, the user should not call render() if we returned false from
|
||||
// beginFrame(). But because this is allowed, we handle it gracefully.
|
||||
|
||||
@@ -656,7 +656,7 @@ AsyncCallId FTexture::setImageAsync(FEngine& engine, size_t const level,
|
||||
return id;
|
||||
}
|
||||
|
||||
void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept {
|
||||
void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) {
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
@@ -678,7 +678,7 @@ void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) n
|
||||
setHandles(texture);
|
||||
}
|
||||
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image) noexcept {
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image) {
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
@@ -700,7 +700,7 @@ void FTexture::setExternalImage(FEngine& engine, void* image) noexcept {
|
||||
setHandles(texture);
|
||||
}
|
||||
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image, size_t const plane) noexcept {
|
||||
void FTexture::setExternalImage(FEngine& engine, void* image, size_t const plane) {
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
@@ -723,7 +723,7 @@ void FTexture::setExternalImage(FEngine& engine, void* image, size_t const plane
|
||||
setHandles(texture);
|
||||
}
|
||||
|
||||
void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept {
|
||||
void FTexture::setExternalStream(FEngine& engine, FStream* stream) {
|
||||
FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external.";
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
@@ -750,7 +750,7 @@ void FTexture::setExternalStream(FEngine& engine, FStream* stream) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void FTexture::generateMipmaps(FEngine& engine) const noexcept {
|
||||
void FTexture::generateMipmaps(FEngine& engine) const {
|
||||
FILAMENT_CHECK_PRECONDITION(!mExternal)
|
||||
<< "External Textures are not mipmappable.";
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
@@ -831,14 +831,14 @@ Handle<HwTexture> FTexture::createPlaceholderTexture(
|
||||
return handle;
|
||||
}
|
||||
|
||||
backend::Handle<backend::HwTexture> FTexture::getHwHandle() const noexcept {
|
||||
backend::Handle<backend::HwTexture> FTexture::getHwHandle() const {
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
Handle<HwTexture> FTexture::getHwHandleForSampling() const noexcept {
|
||||
Handle<HwTexture> FTexture::getHwHandleForSampling() const {
|
||||
FILAMENT_CHECK_PRECONDITION(isCreationComplete())
|
||||
<< "Texture is not created yet. It may be in the process of asynchronous loading";
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ public:
|
||||
// frees driver resources, object becomes invalid
|
||||
void terminate(FEngine& engine);
|
||||
|
||||
backend::Handle<backend::HwTexture> getHwHandle() const noexcept;
|
||||
backend::Handle<backend::HwTexture> getHwHandleForSampling() const noexcept;
|
||||
backend::Handle<backend::HwTexture> getHwHandle() const;
|
||||
backend::Handle<backend::HwTexture> getHwHandleForSampling() const;
|
||||
|
||||
size_t getWidth(size_t level = 0) const noexcept;
|
||||
size_t getHeight(size_t level = 0) const noexcept;
|
||||
@@ -73,12 +73,12 @@ public:
|
||||
PixelBufferDescriptor&& buffer, backend::CallbackHandler* handler,
|
||||
AsyncCompletionCallback callback, void* user) const;
|
||||
|
||||
void setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept;
|
||||
void setExternalImage(FEngine& engine, void* image) noexcept;
|
||||
void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept;
|
||||
void setExternalStream(FEngine& engine, FStream* stream) noexcept;
|
||||
void setExternalImage(FEngine& engine, ExternalImageHandleRef image);
|
||||
void setExternalImage(FEngine& engine, void* image);
|
||||
void setExternalImage(FEngine& engine, void* image, size_t plane);
|
||||
void setExternalStream(FEngine& engine, FStream* stream);
|
||||
|
||||
void generateMipmaps(FEngine& engine) const noexcept;
|
||||
void generateMipmaps(FEngine& engine) const;
|
||||
|
||||
bool isCompressed() const noexcept { return isCompressedFormat(mFormat); }
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ const char* FrameGraphResources::getPassName() const noexcept {
|
||||
// this perhaps weirdly returns a reference, this is to express the fact that if this method
|
||||
// fails, it has to assert (or throw), it can't return for e.g. a nullptr, because the public
|
||||
// API doesn't return pointers.
|
||||
// We still use FILAMENT_CHECK_PRECONDITION() because these failures are due to post conditions not met.
|
||||
// We use FILAMENT_CHECK_PRECONDITION() because these failures are due to caller contract violations (preconditions).
|
||||
VirtualResource& FrameGraphResources::getResource(FrameGraphHandle const handle) const {
|
||||
FILAMENT_CHECK_PRECONDITION(handle) << "Uninitialized handle when using FrameGraphResources.";
|
||||
|
||||
|
||||
@@ -78,6 +78,10 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
#include <exception>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "generated/resources/filamentapp.h"
|
||||
@@ -248,6 +252,9 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||
SDL_Window* sdlWindow = window->getSDLWindow();
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
while (!mClosed) {
|
||||
if (mWindowTitle != SDL_GetWindowTitle(sdlWindow)) {
|
||||
SDL_SetWindowTitle(sdlWindow, mWindowTitle.c_str());
|
||||
@@ -262,7 +269,7 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
cameraFocalLength = mCameraFocalLength;
|
||||
cameraNear = mCameraNear;
|
||||
cameraFar = mCameraFar;
|
||||
}
|
||||
}
|
||||
|
||||
if (!UTILS_HAS_THREADING) {
|
||||
mEngine->execute();
|
||||
@@ -371,10 +378,10 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event.window.event) {
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
window->resize();
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -562,6 +569,16 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
++mSkippedFrames;
|
||||
}
|
||||
}
|
||||
#ifdef __EXCEPTIONS
|
||||
} catch (Panic const& e) {
|
||||
LOG(ERROR) << "Filament exception (terminate cleanly): " << e.what();
|
||||
LOG(ERROR) << e.getCallStack();
|
||||
} catch (std::exception const& e) {
|
||||
LOG(ERROR) << "System exception (terminate cleanly): " << e.what();
|
||||
} catch (...) {
|
||||
LOG(ERROR) << "Unknown exception! (terminate cleanly)";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mImGuiHelper) {
|
||||
mImGuiHelper.reset();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
# define UTILS_EXCEPTIONS 1
|
||||
# include <exception>
|
||||
#else
|
||||
# ifdef UTILS_EXCEPTIONS
|
||||
# error UTILS_EXCEPTIONS is already defined!
|
||||
@@ -262,7 +263,11 @@ namespace utils {
|
||||
* The Panic class provides the std::exception protocol, it is the base exception object
|
||||
* used for all thrown exceptions.
|
||||
*/
|
||||
class UTILS_PUBLIC Panic {
|
||||
class UTILS_PUBLIC Panic
|
||||
#ifdef __EXCEPTIONS
|
||||
: public std::exception
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
using PanicHandlerCallback = void(*)(void* user, Panic const& panic);
|
||||
|
||||
@@ -207,8 +207,7 @@ void TPanic<T>::panic(char const* function, char const* file, int const line, ch
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TPanic<T>::panic(char const* function, char const* file, int line, char const* literal,
|
||||
CString reason) {
|
||||
void TPanic<T>::panic(char const* function, char const* file, int line, char const* literal, CString reason) {
|
||||
|
||||
if (reason.empty()) {
|
||||
reason = CString(literal);
|
||||
@@ -216,15 +215,18 @@ void TPanic<T>::panic(char const* function, char const* file, int line, char con
|
||||
|
||||
T e(function, formatFile(file), line, literal, std::move(reason));
|
||||
|
||||
// always log the Panic at the point it is detected
|
||||
#ifndef __EXCEPTIONS
|
||||
// log the Panic at the point it is detected unless we have exceptions, the exception handler will be
|
||||
// responsible for that.
|
||||
e.log();
|
||||
#endif
|
||||
|
||||
// Call the user provided handler
|
||||
UserPanicHandler::get().call(e);
|
||||
|
||||
// if exceptions are enabled, throw now.
|
||||
#ifdef __EXCEPTIONS
|
||||
throw e;
|
||||
throw std::move(e);
|
||||
#endif
|
||||
|
||||
// and finally abort if we somehow get here
|
||||
|
||||
@@ -450,6 +450,8 @@ class_<Engine>("Engine")
|
||||
|
||||
.function("isAutomaticInstancingEnabled", &Engine::isAutomaticInstancingEnabled)
|
||||
|
||||
.function("hasUnrecoverableFailure", &Engine::hasUnrecoverableFailure)
|
||||
|
||||
.function("getSupportedFeatureLevel", &Engine::getSupportedFeatureLevel)
|
||||
|
||||
.function("setActiveFeatureLevel", &Engine::setActiveFeatureLevel)
|
||||
|
||||
Reference in New Issue
Block a user