diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index cf44dad8d3..7c6c7b21a3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,7 +6,9 @@ A new header is inserted each time a *tag* is created. ## main branch ## v1.31.2 + - vulkan: fix memory leak in readPixels +- engine: added support for draw-commands channels (stronger ordering of commands/renderables) ## v1.31.1 diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp index 6a1b32c622..74c3c7dece 100644 --- a/android/filament-android/src/main/cpp/RenderableManager.cpp +++ b/android/filament-android/src/main/cpp/RenderableManager.cpp @@ -150,6 +150,13 @@ Java_com_google_android_filament_RenderableManager_nBuilderPriority(JNIEnv*, jcl builder->priority((uint8_t) priority); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nBuilderChannel(JNIEnv*, jclass, + jlong nativeBuilder, jint channel) { + RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; + builder->channel((uint8_t) channel); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_RenderableManager_nBuilderCulling(JNIEnv*, jclass, jlong nativeBuilder, jboolean enabled) { @@ -339,6 +346,13 @@ Java_com_google_android_filament_RenderableManager_nSetPriority(JNIEnv*, jclass, rm->setPriority((RenderableManager::Instance) i, (uint8_t) priority); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nSetChannel(JNIEnv*, jclass, + jlong nativeRenderableManager, jint i, jint channel) { + RenderableManager *rm = (RenderableManager *) nativeRenderableManager; + rm->setChannel((RenderableManager::Instance) i, (uint8_t) channel); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_RenderableManager_nSetCulling(JNIEnv*, jclass, jlong nativeRenderableManager, jint i, jboolean enabled) { 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 ddb2cce5ca..0b56f95d78 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 @@ -257,23 +257,74 @@ public class RenderableManager { * Provides coarse-grained control over draw order. * *
In general Filament reserves the right to re-order renderables to allow for efficient - * rendering. However clients can control ordering at a coarse level using priority.
+ * rendering. However clients can control ordering at a coarse level using \em priority. + * The priority is applied separately for opaque and translucent objects, that is, opaque + * objects are always drawn before translucent objects regardless of the priority. * *For example, this could be used to draw a semitransparent HUD, if a client wishes to * avoid using a separate View for the HUD. Note that priority is completely orthogonal to * {@link Builder#layerMask}, which merely controls visibility.
+ + *The Skybox always using the lowest priority, so it's drawn last, which may improve + * performance.
* *The priority is clamped to the range [0..7], defaults to 4; 7 is lowest priority * (rendered last).
* * @see Builder#blendOrder */ + + /** + * Provides coarse-grained control over draw order. + * + *In general Filament reserves the right to re-order renderables to allow for efficient + * rendering. However clients can control ordering at a coarse level using priority. + * The priority is applied separately for opaque and translucent objects, that is, opaque + * objects are always drawn before translucent objects regardless of the priority.
+ * + *For example, this could be used to draw a semitransparent HUD, if a client wishes to + * avoid using a separate View for the HUD. Note that priority is completely orthogonal to + * {@link Builder#layerMask}, which merely controls visibility.
+ + *The Skybox always using the lowest priority, so it's drawn last, which may improve + * performance.
+ * + * @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority + * (rendered last). + * + * @return Builder reference for chaining calls. + * + * @see Builder#channel + * @see Builder#blendOrder + * @see #setPriority + * @see #setBlendOrderAt + */ @NonNull public Builder priority(@IntRange(from = 0, to = 7) int priority) { nBuilderPriority(mNativeBuilder, priority); return this; } + /** + * Set the channel this renderable is associated to. There can be 4 channels. + * All renderables in a given channel are rendered together, regardless of anything else. + * They are sorted as usual withing a channel. + * Channels work similarly to priorities, except that they enforce the strongest ordering. + * + * @param channel clamped to the range [0..3], defaults to 0. + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::priority() + * @see RenderableManager::setBlendOrderAt() + */ + @NonNull + public Builder channel(@IntRange(from = 0, to = 3) int channel) { + nBuilderChannel(mNativeBuilder, channel); + return this; + } + /** * Controls frustum culling, true by default. * @@ -655,6 +706,15 @@ public class RenderableManager { nSetPriority(mNativeObject, i, priority); } + /** + * Changes the channel of a renderable + * + * @see Builder#channel + */ + public void setChannel(@EntityInstance int i, @IntRange(from = 0, to = 3) int channel) { + nSetChannel(mNativeObject, i, channel); + } + /** * Changes whether or not frustum culling is on. * @@ -876,6 +936,7 @@ public class RenderableManager { private static native void nBuilderBoundingBox(long nativeBuilder, float cx, float cy, float cz, float ex, float ey, float ez); private static native void nBuilderLayerMask(long nativeBuilder, int select, int value); private static native void nBuilderPriority(long nativeBuilder, int priority); + private static native void nBuilderChannel(long nativeBuilder, int channel); private static native void nBuilderCulling(long nativeBuilder, boolean enabled); private static native void nBuilderCastShadows(long nativeBuilder, boolean enabled); private static native void nBuilderReceiveShadows(long nativeBuilder, boolean enabled); @@ -898,6 +959,7 @@ public class RenderableManager { private static native void nSetAxisAlignedBoundingBox(long nativeRenderableManager, int i, float cx, float cy, float cz, float ex, float ey, float ez); private static native void nSetLayerMask(long nativeRenderableManager, int i, int select, int value); private static native void nSetPriority(long nativeRenderableManager, int i, int priority); + private static native void nSetChannel(long nativeRenderableManager, int i, int channel); private static native void nSetCulling(long nativeRenderableManager, int i, boolean enabled); private static native void nSetLightChannel(long nativeRenderableManager, int i, int channel, boolean enable); private static native boolean nGetLightChannel(long nativeRenderableManager, int i, int channel); diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 737b8b4703..447998fa45 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -206,20 +206,44 @@ public: * * In general Filament reserves the right to re-order renderables to allow for efficient * rendering. However clients can control ordering at a coarse level using \em priority. + * The priority is applied separately for opaque and translucent objects, that is, opaque + * objects are always drawn before translucent objects regardless of the priority. * - * For example, this could be used to draw a semitransparent HUD, if a client wishes to - * avoid using a separate View for the HUD. Note that priority is completely orthogonal to + * For example, this could be used to draw a semitransparent HUD on top of everything, + * without using a separate View. Note that priority is completely orthogonal to * Builder::layerMask, which merely controls visibility. * + * The Skybox always using the lowest priority, so it's drawn last, which may improve + * performance. + * * @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority * (rendered last). * * @return Builder reference for chaining calls. * - * @see Builder::blendOrder(), RenderableManager::setBlendOrderAt() + * @see Builder::blendOrder() + * @see Builder::channel() + * @see RenderableManager::setPriority() + * @see RenderableManager::setBlendOrderAt() */ Builder& priority(uint8_t priority) noexcept; + /** + * Set the channel this renderable is associated to. There can be 4 channels. + * All renderables in a given channel are rendered together, regardless of anything else. + * They are sorted as usual withing a channel. + * Channels work similarly to priorities, except that they enforce the strongest ordering. + * + * @param channel clamped to the range [0..3], defaults to 0. + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::priority() + * @see RenderableManager::setBlendOrderAt() + */ + Builder& channel(uint8_t channel) noexcept; + /** * Controls frustum culling, true by default. * @@ -461,6 +485,13 @@ public: */ void setPriority(Instance instance, uint8_t priority) noexcept; + /** + * Changes the channel a renderable is associated to. + * + * \see Builder::channel(). + */ + void setChannel(Instance instance, uint8_t channel) noexcept; + /** * Changes whether or not frustum culling is on. * diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 791f9d49e5..99643f152c 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -148,15 +148,18 @@ void RenderPass::appendCommands(FEngine& engine, CommandTypeFlags const commandT } } -void RenderPass::appendCustomCommand(Pass pass, CustomCommand custom, uint32_t order, +void RenderPass::appendCustomCommand(uint8_t channel, Pass pass, CustomCommand custom, uint32_t order, Executor::CustomCommandFn command) { - assert((uint64_t(order) << CUSTOM_ORDER_SHIFT) <= CUSTOM_ORDER_MASK); + assert_invariant((uint64_t(order) << CUSTOM_ORDER_SHIFT) <= CUSTOM_ORDER_MASK); - uint32_t index = mCustomCommands.size(); + channel = std::min(channel, uint8_t(0x3)); + + uint32_t const index = mCustomCommands.size(); mCustomCommands.push_back(std::move(command)); uint64_t cmd = uint64_t(pass); + cmd |= uint64_t(channel) << CHANNEL_SHIFT; cmd |= uint64_t(custom); cmd |= uint64_t(order) << CUSTOM_ORDER_SHIFT; cmd |= uint64_t(index); @@ -508,6 +511,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, const bool hasSkinningOrMorphing = soaVisibility[i].skinning || hasMorphing; cmdColor.key = makeField(soaVisibility[i].priority, PRIORITY_MASK, PRIORITY_SHIFT); + cmdColor.key |= makeField(soaVisibility[i].channel, CHANNEL_MASK, CHANNEL_SHIFT); cmdColor.primitive.index = (uint16_t)i; cmdColor.primitive.instanceCount = soaInstanceCount[i]; @@ -522,6 +526,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdDepth.key = uint64_t(Pass::DEPTH); cmdDepth.key |= uint64_t(CustomCommand::PASS); cmdDepth.key |= makeField(soaVisibility[i].priority, PRIORITY_MASK, PRIORITY_SHIFT); + cmdDepth.key |= makeField(soaVisibility[i].channel, CHANNEL_MASK, CHANNEL_SHIFT); cmdDepth.key |= makeField(distanceBits >> 22u, Z_BUCKET_MASK, Z_BUCKET_SHIFT); cmdDepth.primitive.index = (uint16_t)i; cmdDepth.primitive.instanceCount = soaInstanceCount[i]; diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index d3f48ea34e..5d4476c767 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -49,6 +49,8 @@ public: * Command key encoding * -------------------- * + * CC = Channel + * PP = Pass * a = alpha masking * ppp = priority * t = two-pass transparency ordering @@ -58,45 +60,45 @@ public: * TODO: we need to add a "primitive id" in the low-bits of material-id, so that * auto-instancing can work better * - * DEPTH command - * | 6 | 2| 2|1| 3 | 2| 6 | 10 | 32 | - * +------+--+--+-+---+--+------+----------+--------------------------------+ - * |000000|01|00|0|ppp|00|000000| Z-bucket | material-id | - * +------+--+--+-+---+--+------+----------+--------------------------------+ - * | correctness | optimizations (truncation allowed) | + * DEPTH command (b00) + * | | | 2| 2| 2|1| 3 | 2| 6 | 10 | 32 | + * +--+--+--+--+--+-+---+--+------+----------+--------------------------------+ + * |CC|00|00|01|00|0|ppp|00|000000| Z-bucket | material-id | + * +--+--+--+--+--+-+---+--+------+----------+--------------------------------+ + * | correctness | optimizations (truncation allowed) | * * - * COLOR command - * | 6 | 2| 2|1| 3 | 2| 6 | 10 | 32 | - * +------+--+--+-+---+--+------+----------+--------------------------------+ - * |000001|01|00|a|ppp|00|000000| Z-bucket | material-id | - * |000010|01|00|a|ppp|00|000000| Z-bucket | material-id | refraction - * +------+--+--+-+---+--+------+----------+--------------------------------+ - * | correctness | optimizations (truncation allowed) | + * COLOR (b01) and REFRACT (b10) commands + * | | 2| 2| 2| 2|1| 3 | 2| 6 | 10 | 32 | + * +--+--+--+--+--+-+---+--+------+----------+--------------------------------+ + * |CC|00|01|01|00|a|ppp|00|000000| Z-bucket | material-id | + * |CC|00|10|01|00|a|ppp|00|000000| Z-bucket | material-id | refraction + * +--+--+--+--+--+-+---+--+------+----------+--------------------------------+ + * | correctness | optimizations (truncation allowed) | * * - * BLENDED command - * | 6 | 2| 2|1| 3 | 2| 32 | 15 |1| - * +------+--+--+-+---+--+--------------------------------+---------------+-+ - * |000011|01|00|0|ppp|00| ~distanceBits | blendOrder |t| - * +------+--+--+-+---+--+--------------------------------+---------------+-+ - * | correctness | + * BLENDED command (b11) + * | 2| 2| 2| 2| 2|1| 3 | 2| 32 | 15 |1| + * +--+--+--+--+--+-+---+--+--------------------------------+---------------+-+ + * |CC|00|11|01|00|0|ppp|00| ~distanceBits | blendOrder |t| + * +--+--+--+--+--+-+---+--+--------------------------------+---------------+-+ + * | correctness | * * * pre-CUSTOM command - * | 6 | 2| 2| 22 | 32 | - * +------+--+--+----------------------+--------------------------------+ - * | pass |00|00| order | custom command index | - * +------+--+--+----------------------+--------------------------------+ - * | correctness | + * | 2| 2| 2| 2| 2| 22 | 32 | + * +--+--+--+--+--+----------------------+--------------------------------+ + * |CC|00|PP|00|00| order | custom command index | + * +--+--+--+--+--+----------------------+--------------------------------+ + * | correctness | * * * post-CUSTOM command - * | 6 | 2| 2| 22 | 32 | - * +------+--+--+----------------------+--------------------------------+ - * | pass |11|00| order | custom command index | - * +------+--+--+----------------------+--------------------------------+ - * | correctness | + * | 2| 2| 2| 2| 2| 22 | 32 | + * +--+--+--+--+--+----------------------+--------------------------------+ + * |CC|00|PP|11|00| order | custom command index | + * +--+--+--+--+--+----------------------+--------------------------------+ + * | correctness | * * * SENTINEL command @@ -137,12 +139,15 @@ public: static constexpr uint64_t BLENDING_MASK = 0x0020000000000000llu; static constexpr unsigned BLENDING_SHIFT = 53; - static constexpr uint64_t PASS_MASK = 0xFC00000000000000llu; - static constexpr unsigned PASS_SHIFT = 58; - static constexpr uint64_t CUSTOM_MASK = 0x0300000000000000llu; static constexpr unsigned CUSTOM_SHIFT = 56; + static constexpr uint64_t PASS_MASK = 0x0C00000000000000llu; + static constexpr unsigned PASS_SHIFT = 58; + + static constexpr uint64_t CHANNEL_MASK = 0xC000000000000000llu; + static constexpr unsigned CHANNEL_SHIFT = 62; + static constexpr uint64_t CUSTOM_ORDER_MASK = 0x003FFFFF00000000llu; static constexpr unsigned CUSTOM_ORDER_SHIFT = 32; @@ -373,7 +378,7 @@ public: } // Appends a custom command. - void appendCustomCommand(Pass pass, CustomCommand custom, uint32_t order, + void appendCustomCommand(uint8_t channel, Pass pass, CustomCommand custom, uint32_t order, Executor::CustomCommandFn command); diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp index 6b6e9637ad..5a16d8d63a 100644 --- a/filament/src/RenderableManager.cpp +++ b/filament/src/RenderableManager.cpp @@ -52,6 +52,10 @@ void RenderableManager::setPriority(Instance instance, uint8_t priority) noexcep downcast(this)->setPriority(instance, priority); } +void RenderableManager::setChannel(Instance instance, uint8_t channel) noexcept{ + downcast(this)->setChannel(instance, channel); +} + void RenderableManager::setCulling(Instance instance, bool enable) noexcept { downcast(this)->setCulling(instance, enable); } diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index ae3b47f2cf..335ed53212 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -51,7 +51,8 @@ struct RenderableManager::BuilderDetails { Box mAABB; uint8_t mLayerMask = 0x1; uint8_t mPriority = 0x4; - uint8_t mChannels = 1; + uint8_t mCommandChannel = 0x0; + uint8_t mLightChannels = 1; uint16_t mInstanceCount = 1; bool mCulling : 1; bool mCastShadows : 1; @@ -135,6 +136,11 @@ RenderableManager::Builder& RenderableManager::Builder::priority(uint8_t priorit return *this; } +RenderableManager::Builder& RenderableManager::Builder::channel(uint8_t channel) noexcept { + mImpl->mCommandChannel = std::min(channel, uint8_t(0x3)); + return *this; +} + RenderableManager::Builder& RenderableManager::Builder::culling(bool enable) noexcept { mImpl->mCulling = enable; return *this; @@ -143,8 +149,8 @@ RenderableManager::Builder& RenderableManager::Builder::culling(bool enable) noe RenderableManager::Builder& RenderableManager::Builder::lightChannel(unsigned int channel, bool enable) noexcept { if (channel < 8) { const uint8_t mask = 1u << channel; - mImpl->mChannels &= ~mask; - mImpl->mChannels |= enable ? mask : 0u; + mImpl->mLightChannels &= ~mask; + mImpl->mLightChannels |= enable ? mask : 0u; } return *this; } @@ -338,13 +344,14 @@ void FRenderableManager::create( setAxisAlignedBoundingBox(ci, builder->mAABB); setLayerMask(ci, builder->mLayerMask); setPriority(ci, builder->mPriority); + setChannel(ci, builder->mCommandChannel); setCastShadows(ci, builder->mCastShadows); setReceiveShadows(ci, builder->mReceiveShadows); setScreenSpaceContactShadows(ci, builder->mScreenSpaceContactShadows); setCulling(ci, builder->mCulling); setSkinning(ci, false); setMorphing(ci, builder->mMorphTargetCount); - mManager[ci].channels = builder->mChannels; + mManager[ci].channels = builder->mLightChannels; mManager[ci].instanceCount = builder->mInstanceCount; const uint32_t boneCount = builder->mSkinningBoneCount; diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 11a817ca4f..48e75d7fe2 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -54,6 +54,7 @@ public: // TODO: consider renaming, this pertains to material variants, not strictly visibility. struct Visibility { uint8_t priority : 3; + uint8_t channel : 2; bool castShadows : 1; bool receiveShadows : 1; bool culling : 1; @@ -102,6 +103,9 @@ public: // The priority is clamped to the range [0..7] inline void setPriority(Instance instance, uint8_t priority) noexcept; + // The channel is clamped to the range [0..3] + inline void setChannel(Instance instance, uint8_t channel) noexcept; + inline void setCastShadows(Instance instance, bool enable) noexcept; inline void setLayerMask(Instance instance, uint8_t layerMask) noexcept; @@ -159,7 +163,7 @@ public: return mManager.getEntity(instance); } - inline size_t getLevelCount(Instance) const noexcept { return 1; } + inline size_t getLevelCount(Instance) const noexcept { return 1u; } size_t getPrimitiveCount(Instance instance, uint8_t level) const noexcept; void setMaterialInstanceAt(Instance instance, uint8_t level, size_t primitiveIndex, FMaterialInstance const* materialInstance); @@ -283,7 +287,14 @@ void FRenderableManager::setLayerMask(Instance instance, uint8_t layerMask) noex void FRenderableManager::setPriority(Instance instance, uint8_t priority) noexcept { if (instance) { Visibility& visibility = mManager[instance].visibility; - visibility.priority = priority; + visibility.priority = std::min(priority, uint8_t(0x7)); + } +} + +void FRenderableManager::setChannel(Instance instance, uint8_t channel) noexcept { + if (instance) { + Visibility& visibility = mManager[instance].visibility; + visibility.channel = std::min(channel, uint8_t(0x3)); } } diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 051c16ae9d..c737e05e15 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -913,7 +913,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { if (colorGradingConfigForColor.asSubpass) { // append color grading subpass after all other passes - pass.appendCustomCommand( + pass.appendCustomCommand(3, RenderPass::Pass::BLENDED, RenderPass::CustomCommand::EPILOG, 0, [&ppm, &driver, colorGradingConfigForColor]() { @@ -921,7 +921,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { }); } if (colorGradingConfig.customResolve) { // append custom resolve subpass after all other passes - pass.appendCustomCommand( + pass.appendCustomCommand(3, RenderPass::Pass::BLENDED, RenderPass::CustomCommand::EPILOG, 0, [&ppm, &driver]() { diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index e6a6d0f6da..117be8e4db 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -896,6 +896,9 @@ class_