implement draw command channels

There can be up to 4 channels drawing commands can be associated to. 
Channels work like "priorities" except it's the strongest command ordering 
key, in particular it takes precedence over the object's blending mode.
This commit is contained in:
Mathias Agopian
2023-01-23 13:47:41 -08:00
committed by Mathias Agopian
parent 20cbecfd7c
commit d0c043c7ff
11 changed files with 193 additions and 48 deletions
+2
View File
@@ -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
@@ -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) {
@@ -257,23 +257,74 @@ public class RenderableManager {
* Provides coarse-grained control over draw order.
*
* <p>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</em>.</p>
* 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.</p>
*
* <p>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.</p>
* <p>The Skybox always using the lowest priority, so it's drawn last, which may improve
* performance.</p>
*
* <p>The priority is clamped to the range [0..7], defaults to 4; 7 is lowest priority
* (rendered last).</p>
*
* @see Builder#blendOrder
*/
/**
* Provides coarse-grained control over draw order.
*
* <p>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.</p>
*
* <p>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.</p>
* <p>The Skybox always using the lowest priority, so it's drawn last, which may improve
* performance.</p>
*
* @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);
+34 -3
View File
@@ -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.
*
+8 -3
View File
@@ -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];
+38 -33
View File
@@ -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);
+4
View File
@@ -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);
}
+11 -4
View File
@@ -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;
+13 -2
View File
@@ -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));
}
}
+2 -2
View File
@@ -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]() {
+4
View File
@@ -896,6 +896,9 @@ class_<RenderableBuilder>("RenderableManager$Builder")
.BUILDER_FUNCTION("priority", RenderableBuilder, (RenderableBuilder* builder, uint8_t value), {
return &builder->priority(value); })
.BUILDER_FUNCTION("channel", RenderableBuilder, (RenderableBuilder* builder, uint8_t value), {
return &builder->channel(value); })
.BUILDER_FUNCTION("culling", RenderableBuilder, (RenderableBuilder* builder, bool enable), {
return &builder->culling(enable); })
@@ -965,6 +968,7 @@ class_<RenderableManager>("RenderableManager")
.function("setAxisAlignedBoundingBox", &RenderableManager::setAxisAlignedBoundingBox)
.function("setLayerMask", &RenderableManager::setLayerMask)
.function("setPriority", &RenderableManager::setPriority)
.function("setChannel", &RenderableManager::setChannel)
.function("setCastShadows", &RenderableManager::setCastShadows)
.function("setReceiveShadows", &RenderableManager::setReceiveShadows)
.function("isShadowCaster", &RenderableManager::isShadowCaster)