diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md
index 77a7acc5f46..4a1a9c7fa7e 100644
--- a/NEW_RELEASE_NOTES.md
+++ b/NEW_RELEASE_NOTES.md
@@ -7,5 +7,3 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
-
-- engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()`
diff --git a/README.md b/README.md
index a1dc91cdc6b..f2e6856085d 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
- implementation 'com.google.android.filament:filament-android:1.51.1'
+ implementation 'com.google.android.filament:filament-android:1.51.2'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
-pod 'Filament', '~> 1.51.1'
+pod 'Filament', '~> 1.51.2'
```
### Snapshots
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index ba94019fceb..d60e6d45843 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -7,6 +7,10 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
+## v1.51.2
+
+- engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()`
+
## v1.51.1
diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp
index 2713dffa0b4..4e586179baa 100644
--- a/android/filament-android/src/main/cpp/RenderableManager.cpp
+++ b/android/filament-android/src/main/cpp/RenderableManager.cpp
@@ -104,6 +104,14 @@ Java_com_google_android_filament_RenderableManager_nBuilderGeometry__JIIJJIIII(J
(size_t) count);
}
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_google_android_filament_RenderableManager_nBuilderGeometryType(JNIEnv*, jclass,
+ jlong nativeBuilder, int type) {
+ RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
+ builder->geometryType((RenderableManager::Builder::GeometryType)type);
+}
+
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nBuilderMaterial(JNIEnv*, jclass,
diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
index 68f10986548..97301df9806 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
@@ -243,9 +243,11 @@ public Builder featureLevel(FeatureLevel featureLevel) {
/**
* Sets the initial paused state of the rendering thread.
*
+ *
Warning: This is an experimental API. See {@link Engine#setPaused(boolean)} for
+ * caveats.
+ *
* @param paused Whether to start the rendering thread paused.
* @return A reference to this Builder for chaining calls.
- * @warning Experimental.
*/
public Builder paused(boolean paused) {
nSetBuilderPaused(mNativeBuilder, paused);
@@ -1209,7 +1211,16 @@ public void flush() {
/**
* Pause or resume the rendering thread.
- * @warning Experimental.
+ *
+ *
Warning: This is an experimental API. In particular, note the following caveats.
+ *
+ *
-
+ * Buffer callbacks will never be called as long as the rendering thread is paused.
+ * Do not rely on a buffer callback to unpause the thread.
+ *
-
+ * While the rendering thread is paused, rendering commands will continue to be queued until the
+ * buffer limit is reached. When the limit is reached, the program will abort.
+ *
*/
public void setPaused(boolean paused) {
nSetPaused(getNativeObject(), paused);
diff --git a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
index a3c8f1ff1c2..f7a6319d7a8 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
@@ -175,6 +175,32 @@ public Builder geometry(@IntRange(from = 0) int index, @NonNull PrimitiveType ty
return this;
}
+ /**
+ * Type of geometry for a Renderable
+ */
+ public enum GeometryType {
+ /** dynamic gemoetry has no restriction */
+ DYNAMIC,
+ /** bounds and world space transform are immutable */
+ STATIC_BOUNDS,
+ /** skinning/morphing not allowed and Vertex/IndexBuffer immutables */
+ STATIC
+ }
+
+ /**
+ * Specify whether this renderable has static bounds. In this context his means that
+ * the renderable's bounding box cannot change and that the renderable's transform is
+ * assumed immutable. Changing the renderable's transform via the TransformManager
+ * can lead to corrupted graphics. Note that skinning and morphing are not forbidden.
+ * Disabled by default.
+ * @param enable whether this renderable has static bounds. false by default.
+ */
+ @NonNull
+ public Builder geometryType(GeometryType type) {
+ nBuilderGeometryType(mNativeBuilder, type.ordinal());
+ return this;
+ }
+
/**
* Binds a material instance to the specified primitive.
*
@@ -964,6 +990,7 @@ public long getNativeObject() {
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer);
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int count);
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int minIndex, int maxIndex, int count);
+ private static native void nBuilderGeometryType(long nativeBuilder, int type);
private static native void nBuilderMaterial(long nativeBuilder, int index, long nativeMaterialInstance);
private static native void nBuilderBlendOrder(long nativeBuilder, int index, int blendOrder);
private static native void nBuilderGlobalBlendOrderEnabled(long nativeBuilder, int index, boolean enabled);
diff --git a/android/gradle.properties b/android/gradle.properties
index 685dd260796..c677c8262ab 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
-VERSION_NAME=1.51.1
+VERSION_NAME=1.51.2
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
diff --git a/build.sh b/build.sh
index d9a778c7ba2..56562cc1c6c 100755
--- a/build.sh
+++ b/build.sh
@@ -516,7 +516,7 @@ function build_android {
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
for sample in ${ANDROID_SAMPLES}; do
echo "Installing out/${sample}-debug.apk"
- cp samples/${sample}/build/outputs/apk/debug/${sample}-debug-unsigned.apk \
+ cp samples/${sample}/build/outputs/apk/debug/${sample}-debug.apk \
../out/${sample}-debug.apk
done
fi
diff --git a/filament/backend/include/backend/Program.h b/filament/backend/include/backend/Program.h
index 97deb6c586b..fe1c4a9b6e8 100644
--- a/filament/backend/include/backend/Program.h
+++ b/filament/backend/include/backend/Program.h
@@ -116,6 +116,8 @@ class Program {
Program& cacheId(uint64_t cacheId) noexcept;
+ Program& multiview(bool multiview) noexcept;
+
ShaderSource const& getShadersSource() const noexcept { return mShadersSource; }
ShaderSource& getShadersSource() noexcept { return mShadersSource; }
@@ -143,6 +145,8 @@ class Program {
uint64_t getCacheId() const noexcept { return mCacheId; }
+ bool isMultiview() const noexcept { return mMultiview; }
+
CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; }
private:
@@ -158,6 +162,11 @@ class Program {
utils::FixedCapacityVector> mAttributes;
std::array mBindingUniformInfo;
CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH;
+ // Indicates the current engine was initialized with multiview stereo, and the variant for this
+ // program contains STE flag. This will be referred later for the OpenGL shader compiler to
+ // determine whether shader code replacement for the num_views should be performed.
+ // This variable could be promoted as a more generic variable later if other similar needs occur.
+ bool mMultiview = false;
};
} // namespace filament::backend
diff --git a/filament/backend/src/CommandBufferQueue.cpp b/filament/backend/src/CommandBufferQueue.cpp
index 9de07ed0e27..b721ce0c50f 100644
--- a/filament/backend/src/CommandBufferQueue.cpp
+++ b/filament/backend/src/CommandBufferQueue.cpp
@@ -58,6 +58,7 @@ void CommandBufferQueue::requestExit() {
}
void CommandBufferQueue::setPaused(bool paused) {
+ std::lock_guard const lock(mLock);
if (paused) {
mPaused = true;
} else {
@@ -125,6 +126,9 @@ void CommandBufferQueue::flush() noexcept {
#endif
SYSTRACE_NAME("waiting: CircularBuffer::flush()");
+ ASSERT_POSTCONDITION(!mPaused,
+ "CommandStream is full, but since the rendering thread is paused, "
+ "the buffer cannot flush and we will deadlock. Instead, abort.");
mCondition.wait(lock, [this, requiredSize]() -> bool {
// TODO: on macOS, we need to call pumpEvents from time to time
return mFreeSpace >= requiredSize;
diff --git a/filament/backend/src/Program.cpp b/filament/backend/src/Program.cpp
index 1bae22d97d0..dc92e8c2a26 100644
--- a/filament/backend/src/Program.cpp
+++ b/filament/backend/src/Program.cpp
@@ -91,6 +91,11 @@ Program& Program::cacheId(uint64_t cacheId) noexcept {
return *this;
}
+Program& Program::multiview(bool multiview) noexcept {
+ mMultiview = multiview;
+ return *this;
+}
+
io::ostream& operator<<(io::ostream& out, const Program& builder) {
out << "Program{";
builder.mLogger(out);
diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp
index e4668e33306..196d1bd2e66 100644
--- a/filament/backend/src/opengl/OpenGLDriver.cpp
+++ b/filament/backend/src/opengl/OpenGLDriver.cpp
@@ -2472,7 +2472,9 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
size_t const stride = p.stride ? p.stride : width;
size_t const bpp = PBD::computeDataSize(p.format, p.type, 1, 1, 1);
size_t const bpr = PBD::computeDataSize(p.format, p.type, stride, 1, p.alignment);
- void const* const buffer = static_cast(p.buffer) + p.left * bpp + bpr * p.top;
+ size_t const bpl = bpr * height; // TODO: PBD should have a "layer stride"
+ void const* const buffer = static_cast(p.buffer)
+ + bpp* p.left + bpr * p.top + bpl * 0; // TODO: PBD should have a p.depth
switch (t->target) {
case SamplerType::SAMPLER_EXTERNAL:
diff --git a/filament/backend/src/opengl/ShaderCompilerService.cpp b/filament/backend/src/opengl/ShaderCompilerService.cpp
index 3c1f57f8329..5b9397ddd4b 100644
--- a/filament/backend/src/opengl/ShaderCompilerService.cpp
+++ b/filament/backend/src/opengl/ShaderCompilerService.cpp
@@ -30,6 +30,7 @@
#include
#include
+#include
#include
#include
#include
@@ -264,6 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
compileShaders(gl,
std::move(program.getShadersSource()),
program.getSpecializationConstants(),
+ program.isMultiview(),
shaders,
token->shaderSourceCode);
@@ -299,6 +301,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
compileShaders(gl,
std::move(program.getShadersSource()),
program.getSpecializationConstants(),
+ program.isMultiview(),
token->gl.shaders,
token->shaderSourceCode);
@@ -501,6 +504,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
void ShaderCompilerService::compileShaders(OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector const& specializationConstants,
+ bool multiview,
std::array& outShaders,
UTILS_UNUSED_IN_RELEASE std::array& outShaderSourceCode) noexcept {
@@ -514,8 +518,16 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
};
std::string specializationConstantString;
+ int32_t numViews = 2;
for (auto const& sc : specializationConstants) {
appendSpecConstantString(specializationConstantString, sc);
+ if (sc.id == 8) {
+ // This constant must match
+ // ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT
+ // which we can't use here because it's defined in EngineEnums.h.
+ // (we're breaking layering here, but it's for the good cause).
+ numViews = std::get(sc.value);
+ }
}
if (!specializationConstantString.empty()) {
specializationConstantString += '\n';
@@ -544,17 +556,23 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
if (UTILS_LIKELY(!shadersSource[i].empty())) {
Program::ShaderBlob& shader = shadersSource[i];
+ char* shader_src = reinterpret_cast(shader.data());
+ size_t shader_len = shader.size();
// remove GOOGLE_cpp_style_line_directive
- std::string_view const source = process_GOOGLE_cpp_style_line_directive(context,
- reinterpret_cast(shader.data()), shader.size());
+ process_GOOGLE_cpp_style_line_directive(context, shader_src, shader_len);
+
+ // replace the value of layout(num_views = X) for multiview extension
+ if (multiview && stage == ShaderStage::VERTEX) {
+ process_OVR_multiview2(context, numViews, shader_src, shader_len);
+ }
// add support for ARB_shading_language_packing if needed
auto const packingFunctions = process_ARB_shading_language_packing(context);
// split shader source, so we can insert the specialization constants and the packing
// functions
- auto const [prolog, body] = splitShaderSource(source);
+ auto const [prolog, body] = splitShaderSource({ shader_src, shader_len });
const std::array sources = {
prolog.data(),
@@ -577,7 +595,7 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
#ifndef NDEBUG
// for debugging we return the original shader source (without the modifications we
// made here), otherwise the line numbers wouldn't match.
- outShaderSourceCode[i] = { source.data(), source.length() };
+ outShaderSourceCode[i] = { shader_src, shader_len };
#endif
outShaders[i] = shaderId;
@@ -586,15 +604,59 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
}
// If usages of the Google-style line directive are present, remove them, as some
-// drivers don't allow the quotation marks. This happens in-place.
-std::string_view ShaderCompilerService::process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
+// drivers don't allow the quotation marks. This source modification happens in-place.
+void ShaderCompilerService::process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
char* source, size_t len) noexcept {
if (!context.ext.GOOGLE_cpp_style_line_directive) {
if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension({ source, len }))) {
removeGoogleLineDirectives(source, len); // length is unaffected
}
}
- return { source, len };
+}
+
+// Look up the `source` to replace the number of eyes for multiview with the given number. This is
+// necessary for OpenGL because OpenGL relies on the number specified in shader files to determine
+// the number of views, which is assumed as a single digit, for multiview.
+// This source modification happens in-place.
+void ShaderCompilerService::process_OVR_multiview2(OpenGLContext& context,
+ int32_t eyeCount, char* source, size_t len) noexcept {
+ // We don't use regular expression in favor of performance.
+ if (context.ext.OVR_multiview2) {
+ const std::string_view shader{ source, len };
+ const std::string_view layout = "layout";
+ const std::string_view num_views = "num_views";
+ size_t found = 0;
+ while (true) {
+ found = shader.find(layout, found);
+ if (found == std::string_view::npos) {
+ break;
+ }
+ found = shader.find_first_not_of(' ', found + layout.size());
+ if (found == std::string_view::npos || shader[found] != '(') {
+ continue;
+ }
+ found = shader.find_first_not_of(' ', found + 1);
+ if (found == std::string_view::npos) {
+ continue;
+ }
+ if (shader.compare(found, num_views.size(), num_views) != 0) {
+ continue;
+ }
+ found = shader.find_first_not_of(' ', found + num_views.size());
+ if (found == std::string_view::npos || shader[found] != '=') {
+ continue;
+ }
+ found = shader.find_first_not_of(' ', found + 1);
+ if (found == std::string_view::npos) {
+ continue;
+ }
+ // We assume the value should be one-digit number.
+ assert_invariant(eyeCount < 10);
+ assert_invariant(!::isdigit(source[found + 1]));
+ source[found] = '0' + eyeCount;
+ break;
+ }
+ }
}
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
diff --git a/filament/backend/src/opengl/ShaderCompilerService.h b/filament/backend/src/opengl/ShaderCompilerService.h
index edd89aafdbb..27255ea0002 100644
--- a/filament/backend/src/opengl/ShaderCompilerService.h
+++ b/filament/backend/src/opengl/ShaderCompilerService.h
@@ -134,10 +134,14 @@ class ShaderCompilerService {
OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector const& specializationConstants,
+ bool multiview,
std::array& outShaders,
std::array& outShaderSourceCode) noexcept;
- static std::string_view process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
+ static void process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
+ char* source, size_t len) noexcept;
+
+ static void process_OVR_multiview2(OpenGLContext& context, int32_t eyeCount,
char* source, size_t len) noexcept;
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
diff --git a/filament/backend/src/vulkan/VulkanConstants.h b/filament/backend/src/vulkan/VulkanConstants.h
index 5856e391641..b4974950ef5 100644
--- a/filament/backend/src/vulkan/VulkanConstants.h
+++ b/filament/backend/src/vulkan/VulkanConstants.h
@@ -43,9 +43,12 @@
// Enables Android systrace
#define FVK_DEBUG_SYSTRACE 0x00000001
-// Group markers are used to denote collection of GPU commands. It is typically at the granualarity
-// of a renderpass.
-#define FVK_DEBUG_GROUP_MARKERS 0x00000002
+// Group markers are used to denote collections of GPU commands. It is typically at the
+// granualarity of a renderpass. You can enable this along with FVK_DEBUG_DEBUG_UTILS to take
+// advantage of vkCmdBegin/EndDebugUtilsLabelEXT. You can also just enable this with
+// FVK_DEBUG_PRINT_GROUP_MARKERS to print the current marker to stdout.
+#define FVK_DEBUG_GROUP_MARKERS 0x00000002
+
#define FVK_DEBUG_TEXTURE 0x00000004
#define FVK_DEBUG_LAYOUT_TRANSITION 0x00000008
#define FVK_DEBUG_COMMAND_BUFFER 0x00000010
@@ -63,9 +66,11 @@
// Enable the debug utils extension if it is available.
#define FVK_DEBUG_DEBUG_UTILS 0x00008000
+// Use this to debug potential Handle/Resource leakage. It will print out reference counts for all
+// the currently active resources.
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
-// Usefaul default combinations
+// Useful default combinations
#define FVK_DEBUG_EVERYTHING 0xFFFFFFFF
#define FVK_DEBUG_PERFORMANCE \
FVK_DEBUG_SYSTRACE
diff --git a/filament/backend/src/vulkan/VulkanFboCache.cpp b/filament/backend/src/vulkan/VulkanFboCache.cpp
index 009ca0273ca..f4b222b1545 100644
--- a/filament/backend/src/vulkan/VulkanFboCache.cpp
+++ b/filament/backend/src/vulkan/VulkanFboCache.cpp
@@ -239,7 +239,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
.format = config.colorFormat[i],
.samples = (VkSampleCountFlagBits) config.samples,
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
- .storeOp = config.samples == 1 ? kEnableStore : kDisableStore,
+ .storeOp = kEnableStore,
.stencilLoadOp = kDontCare,
.stencilStoreOp = kDisableStore,
.initialLayout = ((!discard && config.initialColorLayoutMask & (1 << i)) || clear)
diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h
index 7c65915d51f..f6158c77ae9 100644
--- a/filament/backend/src/vulkan/VulkanHandles.h
+++ b/filament/backend/src/vulkan/VulkanHandles.h
@@ -77,7 +77,11 @@ struct VulkanProgram : public HwProgram, VulkanResource {
struct PipelineInfo {
PipelineInfo()
- : bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff) {}
+ : bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff)
+#if FVK_ENABLED_DEBUG_SAMPLER_NAME
+ , bindingToName(MAX_SAMPLER_COUNT, "")
+#endif
+ {}
// This bitset maps to each of the sampler in the sampler groups associated with this
// program, and whether each sampler is used in which shader (i.e. vert, frag, compute).
diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp
index e595f3bec93..f611f40aac7 100644
--- a/filament/backend/src/vulkan/VulkanTexture.cpp
+++ b/filament/backend/src/vulkan/VulkanTexture.cpp
@@ -18,10 +18,10 @@
#include "VulkanTexture.h"
#include "VulkanUtility.h"
+#include
+#include
#include
-#include "DataReshaper.h"
-
#include
using namespace bluevk;
@@ -100,9 +100,13 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
// Filament expects blit() to work with any texture, so we almost always set these usage flags.
// TODO: investigate performance implications of setting these flags.
- const VkImageUsageFlags blittable = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ constexpr VkImageUsageFlags blittable = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ if (any(usage & (TextureUsage::BLIT_DST | TextureUsage::BLIT_SRC))) {
+ imageInfo.usage |= blittable;
+ }
+
if (any(usage & TextureUsage::SAMPLEABLE)) {
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h
index da936f9b453..b741d3abd93 100644
--- a/filament/include/filament/Engine.h
+++ b/filament/include/filament/Engine.h
@@ -408,9 +408,10 @@ class UTILS_PUBLIC Engine {
Builder& featureLevel(FeatureLevel featureLevel) noexcept;
/**
+ * Warning: This is an experimental API. See Engine::setPaused(bool) for caveats.
+ *
* @param paused Whether to start the rendering thread paused.
* @return A reference to this Builder for chaining calls.
- * @warning Experimental.
*/
Builder& paused(bool paused) noexcept;
@@ -841,7 +842,16 @@ class UTILS_PUBLIC Engine {
/**
* Pause or resume rendering thread.
- * @warning Experimental.
+ *
+ * Warning: This is an experimental API. In particular, note the following caveats.
+ *
+ *
-
+ * Buffer callbacks will never be called as long as the rendering thread is paused.
+ * Do not rely on a buffer callback to unpause the thread.
+ *
-
+ * While the rendering thread is paused, rendering commands will continue to be queued until the
+ * buffer limit is reached. When the limit is reached, the program will abort.
+ *
*/
void setPaused(bool paused);
diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h
index bec39e4af05..bb50b7d1db8 100644
--- a/filament/include/filament/RenderableManager.h
+++ b/filament/include/filament/RenderableManager.h
@@ -156,6 +156,15 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI {
*/
static constexpr uint8_t DEFAULT_CHANNEL = 2u;
+ /**
+ * Type of geometry for a Renderable
+ */
+ enum class GeometryType : uint8_t {
+ DYNAMIC, //!< dynamic gemoetry has no restriction
+ STATIC_BOUNDS, //!< bounds and world space transform are immutable
+ STATIC //!< skinning/morphing not allowed and Vertex/IndexBuffer immutables
+ };
+
/**
* Creates a builder for renderable components.
*
@@ -204,6 +213,17 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI {
VertexBuffer* UTILS_NONNULL vertices,
IndexBuffer* UTILS_NONNULL indices) noexcept; //!< \overload
+
+ /**
+ * Specify the type of geometry for this renderable. DYNAMIC geometry has no restriction,
+ * STATIC_BOUNDS geometry means that both the bounds and the world-space transform of the
+ * the renderable are immutable.
+ * STATIC geometry has the same restrictions as STATIC_BOUNDS, but in addition disallows
+ * skinning, morphing and changing the VertexBuffer or IndexBuffer in any way.
+ * @param enable whether this renderable has static bounds. false by default.
+ */
+ Builder& geometryType(GeometryType type) noexcept;
+
/**
* Binds a material instance to the specified primitive.
*
@@ -603,11 +623,12 @@ class UTILS_PUBLIC RenderableManager : public FilamentAPI {
/**
* Changes the bounding box used for frustum culling.
+ * The renderable must not have staticGeometry enabled.
*
* \see Builder::boundingBox()
* \see RenderableManager::getAxisAlignedBoundingBox()
*/
- void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept;
+ void setAxisAlignedBoundingBox(Instance instance, const Box& aabb);
/**
* Changes the visibility bits.
diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp
index 461acba3a20..3f21ce872d4 100644
--- a/filament/src/PostProcessManager.cpp
+++ b/filament/src/PostProcessManager.cpp
@@ -3292,8 +3292,9 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra
SamplerMagFilter filterMag,
SamplerMinFilter filterMin) noexcept {
- assert_invariant(fg.getDescriptor(input).depth > 1);
- assert_invariant(fg.getDescriptor(input).type == SamplerType::SAMPLER_2D_ARRAY);
+ auto& inputTextureDesc = fg.getDescriptor(input);
+ assert_invariant(inputTextureDesc.depth > 1);
+ assert_invariant(inputTextureDesc.type == SamplerType::SAMPLER_2D_ARRAY);
// TODO: add support for sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
@@ -3329,14 +3330,12 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra
.filterMag = filterMag,
.filterMin = filterMin
});
- mi->setParameter("layerIndex", 0);
mi->setParameter("viewport", float4{
float(vp.left) / inputDesc.width,
float(vp.bottom) / inputDesc.height,
float(vp.width) / inputDesc.width,
float(vp.height) / inputDesc.height
});
- mi->commit(driver);
mi->use(driver);
auto pipeline = material.getPipelineState(mEngine);
@@ -3347,18 +3346,19 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra
pipeline.first.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
}
- // Blit the scene rendered to the first layer to the left half of the screen.
- out.params.viewport.width /= 2;
- render(out, pipeline, driver);
+ // The width of each view takes up 1/depth of the screen width.
+ out.params.viewport.width /= inputTextureDesc.depth;
- // Blit the scene rendered to the second layer to the right half of the screen.
- // Don't clear or discard the target to keep the previously rendered left half image.
- mi->setParameter("layerIndex", 1);
- mi->commit(driver);
- out.params.flags.clear = filament::backend::TargetBufferFlags::NONE;
- out.params.flags.discardStart = filament::backend::TargetBufferFlags::NONE;
- out.params.viewport.left += out.params.viewport.width;
- render(out, pipeline, driver);
+ // Render all layers of the texture to the screen side-by-side.
+ for (uint32_t i = 0; i < inputTextureDesc.depth; ++i) {
+ mi->setParameter("layerIndex", i);
+ mi->commit(driver);
+ render(out, pipeline, driver);
+ // From the second draw, don't clear the targetbuffer.
+ out.params.flags.clear = filament::backend::TargetBufferFlags::NONE;
+ out.params.flags.discardStart = filament::backend::TargetBufferFlags::NONE;
+ out.params.viewport.left += out.params.viewport.width;
+ }
});
return ppQuadBlit->output;
diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp
index 71a83bf544c..133dd817c2c 100644
--- a/filament/src/RenderableManager.cpp
+++ b/filament/src/RenderableManager.cpp
@@ -56,7 +56,7 @@ void RenderableManager::destroy(utils::Entity e) noexcept {
return downcast(this)->destroy(e);
}
-void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept {
+void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) {
downcast(this)->setAxisAlignedBoundingBox(instance, aabb);
}
diff --git a/filament/src/ToneMapper.cpp b/filament/src/ToneMapper.cpp
index 2afa58f4be3..9c5a191210c 100644
--- a/filament/src/ToneMapper.cpp
+++ b/filament/src/ToneMapper.cpp
@@ -253,7 +253,7 @@ float3 PBRNeutralToneMapper::operator()(math::float3 color) const noexcept {
color *= newPeak / peak;
float g = 1.0f - 1.0f / (desaturation * (peak - newPeak) + 1.0f);
- return mix(color, float3(1.0f), g);
+ return mix(color, float3(newPeak), g);
}
//------------------------------------------------------------------------------
diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp
index a7f3fee3f21..3bbd85597ce 100644
--- a/filament/src/components/RenderableManager.cpp
+++ b/filament/src/components/RenderableManager.cpp
@@ -58,6 +58,7 @@ struct RenderableManager::BuilderDetails {
bool mScreenSpaceContactShadows : 1;
bool mSkinningBufferMode : 1;
bool mFogEnabled : 1;
+ RenderableManager::Builder::GeometryType mGeometryType : 2;
size_t mSkinningBoneCount = 0;
size_t mMorphTargetCount = 0;
Bone const* mUserBones = nullptr;
@@ -75,7 +76,9 @@ struct RenderableManager::BuilderDetails {
explicit BuilderDetails(size_t count)
: mEntries(count), mCulling(true), mCastShadows(false),
mReceiveShadows(true), mScreenSpaceContactShadows(false),
- mSkinningBufferMode(false), mFogEnabled(true), mBonePairs() {
+ mSkinningBufferMode(false), mFogEnabled(true),
+ mGeometryType(RenderableManager::Builder::GeometryType::DYNAMIC),
+ mBonePairs() {
}
// this is only needed for the explicit instantiation below
BuilderDetails() = default;
@@ -121,6 +124,11 @@ RenderableManager::Builder& RenderableManager::Builder::geometry(size_t index,
return *this;
}
+RenderableManager::Builder& RenderableManager::Builder::geometryType(GeometryType type) noexcept {
+ mImpl->mGeometryType = type;
+ return *this;
+}
+
RenderableManager::Builder& RenderableManager::Builder::material(size_t index,
MaterialInstance const* materialInstance) noexcept {
if (index < mImpl->mEntries.size()) {
@@ -388,11 +396,21 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng
ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT,
"bone count > %u", CONFIG_MAX_BONE_COUNT);
+
ASSERT_PRECONDITION(mImpl->mInstanceCount <= CONFIG_MAX_INSTANCES || !mImpl->mInstanceBuffer,
"instance count is %zu, but instance count is limited to CONFIG_MAX_INSTANCES (%zu) "
"instances when supplying transforms via an InstanceBuffer.",
mImpl->mInstanceCount,
CONFIG_MAX_INSTANCES);
+
+ if (mImpl->mGeometryType == GeometryType::STATIC) {
+ ASSERT_PRECONDITION(mImpl->mSkinningBoneCount > 0,
+ "Skinning can't be used with STATIC geometry");
+
+ ASSERT_PRECONDITION(mImpl->mMorphTargetCount > 0,
+ "Morphing can't be used with STATIC geometry");
+ }
+
if (mImpl->mInstanceBuffer) {
size_t const bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount;
ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount,
@@ -519,6 +537,8 @@ void FRenderableManager::create(
setSkinning(ci, false);
setMorphing(ci, builder->mMorphTargetCount);
setFogEnabled(ci, builder->mFogEnabled);
+ // do this after calling setAxisAlignedBoundingBox
+ static_cast(mManager[ci].visibility).geometryType = builder->mGeometryType;
mManager[ci].channels = builder->mLightChannels;
InstancesInfo& instances = manager[ci].instances;
diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h
index 746c46dbeee..003026baa0d 100644
--- a/filament/src/components/RenderableManager.h
+++ b/filament/src/components/RenderableManager.h
@@ -22,22 +22,30 @@
#include "HwRenderPrimitiveFactory.h"
#include "UniformBuffer.h"
-#include "backend/DriverApiForward.h"
-
-#include
+#include
#include
#include
-#include
-
#include
+#include
+#include
+
+#include
#include
+#include
#include
#include
#include
+#include