Compare commits

..

7 Commits

Author SHA1 Message Date
Benjamin Doherty
ea428a27d1 Merge branch 'rc/1.31.3' into release 2023-02-01 11:54:04 -08:00
Benjamin Doherty
3bef718238 Bump version to 1.31.3 2023-01-24 14:28:21 -08:00
Benjamin Doherty
298e54c32a Release Filament 1.31.2 2023-01-24 14:26:22 -08:00
Ben Doherty
4c82f0259d Add systrace support on Apple platforms (#6480) 2023-01-23 14:11:47 -08:00
Mathias Agopian
d0c043c7ff 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.
2023-01-23 13:47:41 -08:00
Powei Feng
20cbecfd7c vulkan: put getEnabledLayers behind VK_ENABLE_VALIDATION (#6474) 2023-01-18 18:38:53 -08:00
Powei Feng
194defdb1b vulkan: Fix readPixels memory leak (#6473) 2023-01-18 16:35:58 -08:00
23 changed files with 814 additions and 327 deletions

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.31.2'
implementation 'com.google.android.filament:filament-android:1.31.3'
}
```
@@ -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:
```
pod 'Filament', '~> 1.31.2'
pod 'Filament', '~> 1.31.3'
```
### Snapshots

View File

@@ -5,6 +5,11 @@ A new header is inserted each time a *tag* is created.
## main branch
## v1.31.3
- vulkan: fix memory leak in readPixels
- engine: added support for draw-commands channels (stronger ordering of commands/renderables)
## v1.31.2
## v1.31.1

View File

@@ -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) {

View File

@@ -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);

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.31.2
VERSION_NAME=1.31.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -65,7 +65,38 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
utils::slog.e << utils::io::endl;
return VK_FALSE;
}
// These strings need to be allocated outside a function stack
const std::string_view DESIRED_LAYERS[] = {
"VK_LAYER_KHRONOS_validation",
#if FILAMENT_VULKAN_DUMP_API
"VK_LAYER_LUNARG_api_dump",
#endif
#if defined(ENABLE_RENDERDOC)
"VK_LAYER_RENDERDOC_Capture",
#endif
};
FixedCapacityVector<const char*> getEnabledLayers() {
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
const FixedCapacityVector<VkLayerProperties> availableLayers = filament::backend::enumerate(
vkEnumerateInstanceLayerProperties);
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
for (const auto& desired : DESIRED_LAYERS) {
for (const VkLayerProperties& layer : availableLayers) {
const std::string_view availableLayer(layer.layerName);
if (availableLayer == desired) {
enabledLayers.push_back(desired.data());
break;
}
}
}
return enabledLayers;
}
#endif // VK_ENABLE_VALIDATION
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
// Print some driver or MoltenVK information if it is available.
@@ -144,37 +175,6 @@ void printDepthFormats(VkPhysicalDevice device) {
}
}
// These strings need to be allocated outside a function stack
const std::string_view DESIRED_LAYERS[] = {
"VK_LAYER_KHRONOS_validation",
#if FILAMENT_VULKAN_DUMP_API
"VK_LAYER_LUNARG_api_dump",
#endif
#if defined(ENABLE_RENDERDOC)
"VK_LAYER_RENDERDOC_Capture",
#endif
};
FixedCapacityVector<const char*> getEnabledLayers() {
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
const FixedCapacityVector<VkLayerProperties> availableLayers = filament::backend::enumerate(
vkEnumerateInstanceLayerProperties);
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
for (const auto& desired : DESIRED_LAYERS) {
for (const VkLayerProperties& layer : availableLayers) {
const std::string_view availableLayer(layer.layerName);
if (availableLayer == desired) {
enabledLayers.push_back(desired.data());
break;
}
}
}
return enabledLayers;
}
struct InstanceExtensions {
bool debugUtilsSupported = false;
bool portabilityEnumerationSupported = false;

View File

@@ -1453,11 +1453,8 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
}
vkUnmapMemory(device, stagingMemory);
mDisposer.createDisposable((void*)stagingImage, [=] () {
vkDestroyImage(device, stagingImage, nullptr);
vkFreeMemory(device, stagingMemory, nullptr);
});
vkDestroyImage(device, stagingImage, nullptr);
vkFreeMemory(device, stagingMemory, nullptr);
scheduleDestroy(std::move(pbd));
}

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.
*

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];

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);

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);
}

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;

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));
}
}

View File

@@ -201,11 +201,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
mFrameId++;
mViewRenderedCount = 0;
{ // scope for frame id trace
char buf[64];
snprintf(buf, 64, "frame %u", mFrameId);
SYSTRACE_NAME(buf);
}
SYSTRACE_FRAME_ID(mFrameId);
FEngine& engine = mEngine;
FEngine::DriverApi& driver = engine.getDriverApi();
@@ -913,7 +909,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 +917,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]() {

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.31.2"
spec.version = "1.31.3"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.31.2/filament-v1.31.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.31.3/filament-v1.31.3-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -71,7 +71,6 @@ set(SRCS
src/Profiler.cpp
src/sstream.cpp
src/string.cpp
src/Systrace.cpp
src/ThreadUtils.cpp
)
@@ -80,6 +79,7 @@ if (WIN32)
endif()
if (ANDROID)
list(APPEND SRCS src/android/ThermalManager.cpp)
list(APPEND SRCS src/android/Systrace.cpp)
endif()
if (LINUX OR ANDROID)
list(APPEND SRCS src/linux/Condition.cpp)
@@ -88,6 +88,7 @@ if (LINUX OR ANDROID)
endif()
if (APPLE)
list(APPEND SRCS src/darwin/Path.mm)
list(APPEND SRCS src/darwin/Systrace.cpp)
endif()
# ==================================================================================================

View File

@@ -23,17 +23,6 @@
#define SYSTRACE_TAG_FILAMENT (1<<1) // don't change, used in makefiles
#define SYSTRACE_TAG_JOBSYSTEM (1<<2)
#if defined(__ANDROID__)
#include <atomic>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <utils/compiler.h>
/*
* The SYSTRACE_ macros use SYSTRACE_TAG as a the TAG, which should be defined
* before this file is included. If not, the SYSTRACE_TAG_ALWAYS tag will be used.
@@ -43,228 +32,22 @@
#define SYSTRACE_TAG (SYSTRACE_TAG_ALWAYS)
#endif
// enable tracing
#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG)
// Systrace on Apple platforms is fragile and adds overhead, should only be enabled in dev builds.
#ifndef FILAMENT_APPLE_SYSTRACE
#define FILAMENT_APPLE_SYSTRACE 0
#endif
// disable tracing
#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG)
/**
* Creates a Systrace context in the current scope. needed for calling all other systrace
* commands below.
*/
#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___tracer(SYSTRACE_TAG)
// SYSTRACE_NAME traces the beginning and end of the current scope. To trace
// the correct start and end times this macro should be declared first in the
// scope body.
// It also automatically creates a Systrace context
#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name)
// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name.
#define SYSTRACE_CALL() SYSTRACE_NAME(__FUNCTION__)
#define SYSTRACE_NAME_BEGIN(name) \
___tracer.traceBegin(SYSTRACE_TAG, name)
#define SYSTRACE_NAME_END() \
___tracer.traceEnd(SYSTRACE_TAG)
/**
* Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
* contexts, asynchronous events do not need to be nested. The name describes
* the event, and the cookie provides a unique identifier for distinguishing
* simultaneous events. The name and cookie used to begin an event must be
* used to end it.
*/
#define SYSTRACE_ASYNC_BEGIN(name, cookie) \
___tracer.asyncBegin(SYSTRACE_TAG, name, cookie)
/**
* Trace the end of an asynchronous event.
* This should have a corresponding SYSTRACE_ASYNC_BEGIN.
*/
#define SYSTRACE_ASYNC_END(name, cookie) \
___tracer.asyncEnd(SYSTRACE_TAG, name, cookie)
/**
* Traces an integer counter value. name is used to identify the counter.
* This can be used to track how a value changes over time.
*/
#define SYSTRACE_VALUE32(name, val) \
___tracer.value(SYSTRACE_TAG, name, int32_t(val))
#define SYSTRACE_VALUE64(name, val) \
___tracer.value(SYSTRACE_TAG, name, int64_t(val))
// ------------------------------------------------------------------------------------------------
// No user serviceable code below...
// ------------------------------------------------------------------------------------------------
namespace utils {
namespace details {
class Systrace {
public:
enum tags {
NEVER = SYSTRACE_TAG_NEVER,
ALWAYS = SYSTRACE_TAG_ALWAYS,
FILAMENT = SYSTRACE_TAG_FILAMENT,
JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM
// we could define more TAGS here, as we need them.
};
explicit Systrace(uint32_t tag) noexcept {
if (tag) init(tag);
}
static void enable(uint32_t tags) noexcept;
static void disable(uint32_t tags) noexcept;
inline void traceBegin(uint32_t tag, const char* name) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
beginSection(this, name);
}
}
inline void traceEnd(uint32_t tag) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
endSection(this);
}
}
inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
beginAsyncSection(this, name, cookie);
}
}
inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
endAsyncSection(this, name, cookie);
}
}
inline void value(uint32_t tag, const char* name, int32_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
setCounter(this, name, value);
}
}
inline void value(uint32_t tag, const char* name, int64_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
setCounter(this, name, value);
}
}
private:
friend class ScopedTrace;
// whether tracing is supported at all by the platform
using ATrace_isEnabled_t = bool (*)();
using ATrace_beginSection_t = void (*)(const char* sectionName);
using ATrace_endSection_t = void (*)();
using ATrace_beginAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
using ATrace_endAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
using ATrace_setCounter_t = void (*)(const char* counterName, int64_t counterValue);
struct GlobalState {
bool isTracingAvailable;
std::atomic<uint32_t> isTracingEnabled;
int markerFd;
ATrace_isEnabled_t ATrace_isEnabled;
ATrace_beginSection_t ATrace_beginSection;
ATrace_endSection_t ATrace_endSection;
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
ATrace_endAsyncSection_t ATrace_endAsyncSection;
ATrace_setCounter_t ATrace_setCounter;
void (*beginSection)(Systrace* that, const char* name);
void (*endSection)(Systrace* that);
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*setCounter)(Systrace* that, const char* name, int64_t value);
};
static GlobalState sGlobalState;
// per-instance versions for better performance
ATrace_isEnabled_t ATrace_isEnabled;
ATrace_beginSection_t ATrace_beginSection;
ATrace_endSection_t ATrace_endSection;
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
ATrace_endAsyncSection_t ATrace_endAsyncSection;
ATrace_setCounter_t ATrace_setCounter;
void (*beginSection)(Systrace* that, const char* name);
void (*endSection)(Systrace* that);
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*setCounter)(Systrace* that, const char* name, int64_t value);
void init(uint32_t tag) noexcept;
// cached values for faster access, no need to be initialized
bool mIsTracingEnabled;
int mMarkerFd = -1;
pid_t mPid;
static void setup() noexcept;
static void init_once() noexcept;
static bool isTracingEnabled(uint32_t tag) noexcept;
static void begin_body(int fd, int pid, const char* name) noexcept;
static void end_body(int fd, int pid) noexcept;
static void async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
static void async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
static void int64_body(int fd, int pid, const char* name, int64_t value) noexcept;
};
// ------------------------------------------------------------------------------------------------
class ScopedTrace {
public:
// we don't inline this because it's relatively heavy due to a global check
ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mTag(tag) {
mTrace.traceBegin(tag, name);
}
inline ~ScopedTrace() noexcept {
mTrace.traceEnd(mTag);
}
inline void value(uint32_t tag, const char* name, int32_t v) noexcept {
mTrace.value(tag, name, v);
}
inline void value(uint32_t tag, const char* name, int64_t v) noexcept {
mTrace.value(tag, name, v);
}
private:
Systrace mTrace;
const uint32_t mTag;
};
} // namespace details
} // namespace utils
// ------------------------------------------------------------------------------------------------
#else // !ANDROID
// ------------------------------------------------------------------------------------------------
#if defined(__ANDROID__)
#include <utils/android/Systrace.h>
#elif defined(__APPLE__) && FILAMENT_APPLE_SYSTRACE
#include <utils/darwin/Systrace.h>
#else
#define SYSTRACE_ENABLE()
#define SYSTRACE_DISABLE()
#define SYSTRACE_CONTEXT()
#define SYSTRACE_NAME(name)
#define SYSTRACE_FRAME_ID(frame)
#define SYSTRACE_NAME_BEGIN(name)
#define SYSTRACE_NAME_END()
#define SYSTRACE_CALL()

View File

@@ -0,0 +1,250 @@
/*
* Copyright (C) 2023 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_UTILS_ANDROID_SYSTRACE_H
#define TNT_UTILS_ANDROID_SYSTRACE_H
#include <atomic>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <utils/compiler.h>
// enable tracing
#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG)
// disable tracing
#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG)
/**
* Creates a Systrace context in the current scope. needed for calling all other systrace
* commands below.
*/
#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___tracer(SYSTRACE_TAG)
// SYSTRACE_NAME traces the beginning and end of the current scope. To trace
// the correct start and end times this macro should be declared first in the
// scope body.
// It also automatically creates a Systrace context
#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name)
// Denotes that a new frame has started processing.
#define SYSTRACE_FRAME_ID(frame) \
{ /* scope for frame id trace */ \
char buf[64]; \
snprintf(buf, 64, "frame %u", frame); \
SYSTRACE_NAME(buf); \
}
// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name.
#define SYSTRACE_CALL() SYSTRACE_NAME(__FUNCTION__)
#define SYSTRACE_NAME_BEGIN(name) \
___tracer.traceBegin(SYSTRACE_TAG, name)
#define SYSTRACE_NAME_END() \
___tracer.traceEnd(SYSTRACE_TAG)
/**
* Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
* contexts, asynchronous events do not need to be nested. The name describes
* the event, and the cookie provides a unique identifier for distinguishing
* simultaneous events. The name and cookie used to begin an event must be
* used to end it.
*/
#define SYSTRACE_ASYNC_BEGIN(name, cookie) \
___tracer.asyncBegin(SYSTRACE_TAG, name, cookie)
/**
* Trace the end of an asynchronous event.
* This should have a corresponding SYSTRACE_ASYNC_BEGIN.
*/
#define SYSTRACE_ASYNC_END(name, cookie) \
___tracer.asyncEnd(SYSTRACE_TAG, name, cookie)
/**
* Traces an integer counter value. name is used to identify the counter.
* This can be used to track how a value changes over time.
*/
#define SYSTRACE_VALUE32(name, val) \
___tracer.value(SYSTRACE_TAG, name, int32_t(val))
#define SYSTRACE_VALUE64(name, val) \
___tracer.value(SYSTRACE_TAG, name, int64_t(val))
// ------------------------------------------------------------------------------------------------
// No user serviceable code below...
// ------------------------------------------------------------------------------------------------
namespace utils {
namespace details {
class Systrace {
public:
enum tags {
NEVER = SYSTRACE_TAG_NEVER,
ALWAYS = SYSTRACE_TAG_ALWAYS,
FILAMENT = SYSTRACE_TAG_FILAMENT,
JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM
// we could define more TAGS here, as we need them.
};
explicit Systrace(uint32_t tag) noexcept {
if (tag) init(tag);
}
static void enable(uint32_t tags) noexcept;
static void disable(uint32_t tags) noexcept;
inline void traceBegin(uint32_t tag, const char* name) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
beginSection(this, name);
}
}
inline void traceEnd(uint32_t tag) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
endSection(this);
}
}
inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
beginAsyncSection(this, name, cookie);
}
}
inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
endAsyncSection(this, name, cookie);
}
}
inline void value(uint32_t tag, const char* name, int32_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
setCounter(this, name, value);
}
}
inline void value(uint32_t tag, const char* name, int64_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
setCounter(this, name, value);
}
}
private:
friend class ScopedTrace;
// whether tracing is supported at all by the platform
using ATrace_isEnabled_t = bool (*)();
using ATrace_beginSection_t = void (*)(const char* sectionName);
using ATrace_endSection_t = void (*)();
using ATrace_beginAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
using ATrace_endAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
using ATrace_setCounter_t = void (*)(const char* counterName, int64_t counterValue);
struct GlobalState {
bool isTracingAvailable;
std::atomic<uint32_t> isTracingEnabled;
int markerFd;
ATrace_isEnabled_t ATrace_isEnabled;
ATrace_beginSection_t ATrace_beginSection;
ATrace_endSection_t ATrace_endSection;
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
ATrace_endAsyncSection_t ATrace_endAsyncSection;
ATrace_setCounter_t ATrace_setCounter;
void (*beginSection)(Systrace* that, const char* name);
void (*endSection)(Systrace* that);
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*setCounter)(Systrace* that, const char* name, int64_t value);
};
static GlobalState sGlobalState;
// per-instance versions for better performance
ATrace_isEnabled_t ATrace_isEnabled;
ATrace_beginSection_t ATrace_beginSection;
ATrace_endSection_t ATrace_endSection;
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
ATrace_endAsyncSection_t ATrace_endAsyncSection;
ATrace_setCounter_t ATrace_setCounter;
void (*beginSection)(Systrace* that, const char* name);
void (*endSection)(Systrace* that);
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
void (*setCounter)(Systrace* that, const char* name, int64_t value);
void init(uint32_t tag) noexcept;
// cached values for faster access, no need to be initialized
bool mIsTracingEnabled;
int mMarkerFd = -1;
pid_t mPid;
static void setup() noexcept;
static void init_once() noexcept;
static bool isTracingEnabled(uint32_t tag) noexcept;
static void begin_body(int fd, int pid, const char* name) noexcept;
static void end_body(int fd, int pid) noexcept;
static void async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
static void async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
static void int64_body(int fd, int pid, const char* name, int64_t value) noexcept;
};
// ------------------------------------------------------------------------------------------------
class ScopedTrace {
public:
// we don't inline this because it's relatively heavy due to a global check
ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mTag(tag) {
mTrace.traceBegin(tag, name);
}
inline ~ScopedTrace() noexcept {
mTrace.traceEnd(mTag);
}
inline void value(uint32_t tag, const char* name, int32_t v) noexcept {
mTrace.value(tag, name, v);
}
inline void value(uint32_t tag, const char* name, int64_t v) noexcept {
mTrace.value(tag, name, v);
}
private:
Systrace mTrace;
const uint32_t mTag;
};
} // namespace details
} // namespace utils
#endif // TNT_UTILS_ANDROID_SYSTRACE_H

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2023 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_UTILS_DARWIN_SYSTRACE_H
#define TNT_UTILS_DARWIN_SYSTRACE_H
#include <atomic>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <os/log.h>
#include <os/signpost.h>
#include <utils/compiler.h>
#include <stack>
// enable tracing
#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG)
// disable tracing
#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG)
/**
* Creates a Systrace context in the current scope. needed for calling all other systrace
* commands below.
*/
#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___tracer(SYSTRACE_TAG)
// SYSTRACE_NAME traces the beginning and end of the current scope. To trace
// the correct start and end times this macro should be declared first in the
// scope body.
// It also automatically creates a Systrace context
#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name)
// Denotes that a new frame has started processing.
#define SYSTRACE_FRAME_ID(frame) \
::utils::details::Systrace(SYSTRACE_TAG).frameId(SYSTRACE_TAG, frame)
extern thread_local std::stack<const char*> ___tracerSections;
// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name.
#define SYSTRACE_CALL() SYSTRACE_NAME(__PRETTY_FUNCTION__)
#define SYSTRACE_NAME_BEGIN(name) \
___tracerSections.push(name) , \
___tracer.traceBegin(SYSTRACE_TAG, name)
#define SYSTRACE_NAME_END() \
___tracer.traceEnd(SYSTRACE_TAG, ___tracerSections.top()) , \
___tracerSections.pop()
/**
* Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
* contexts, asynchronous events do not need to be nested. The name describes
* the event, and the cookie provides a unique identifier for distinguishing
* simultaneous events. The name and cookie used to begin an event must be
* used to end it.
*/
#define SYSTRACE_ASYNC_BEGIN(name, cookie) \
___tracer.asyncBegin(SYSTRACE_TAG, name, cookie)
/**
* Trace the end of an asynchronous event.
* This should have a corresponding SYSTRACE_ASYNC_BEGIN.
*/
#define SYSTRACE_ASYNC_END(name, cookie) \
___tracer.asyncEnd(SYSTRACE_TAG, name, cookie)
/**
* Traces an integer counter value. name is used to identify the counter.
* This can be used to track how a value changes over time.
*/
#define SYSTRACE_VALUE32(name, val) \
___tracer.value(SYSTRACE_TAG, name, int32_t(val))
#define SYSTRACE_VALUE64(name, val) \
___tracer.value(SYSTRACE_TAG, name, int64_t(val))
// ------------------------------------------------------------------------------------------------
// No user serviceable code below...
// ------------------------------------------------------------------------------------------------
// This is an alternative to os_signpost_emit_with_type that allows non-compile time strings (namely
// for us, __FUNCTION__).
// The trade-off is that this doesn't allow messages to have printf-style formatting.
// It's fine to pass an empty string to __builtin_os_log_format_buffer_size and
// __builtin_os_log_format, because they return the same value for strings without any format
// specifiers.
// This is fragile, so should only be used to assist debugging and never in production.
#define APPLE_SIGNPOST_EMIT(log, type, spid, name, message) \
if (os_signpost_enabled(log)) { \
uint8_t _os_fmt_buf[__builtin_os_log_format_buffer_size("")]; \
_os_signpost_emit_with_name_impl( \
&__dso_handle, log, type, spid, \
name, message, \
(uint8_t *)__builtin_os_log_format(_os_fmt_buf, ""), \
(uint32_t)sizeof(_os_fmt_buf)); \
}
namespace utils {
namespace details {
class Systrace {
public:
enum tags {
NEVER = SYSTRACE_TAG_NEVER,
ALWAYS = SYSTRACE_TAG_ALWAYS,
FILAMENT = SYSTRACE_TAG_FILAMENT,
JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM
// we could define more TAGS here, as we need them.
};
explicit Systrace(uint32_t tag) noexcept {
if (tag) init(tag);
}
static void enable(uint32_t tags) noexcept;
static void disable(uint32_t tags) noexcept;
inline void traceBegin(uint32_t tag, const char* name) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_INTERVAL_BEGIN,
OS_SIGNPOST_ID_EXCLUSIVE, name, name)
}
}
inline void traceEnd(uint32_t tag, const char* name) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_INTERVAL_END,
OS_SIGNPOST_ID_EXCLUSIVE, name, "")
}
}
inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
// TODO
}
}
inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
// TODO
}
}
inline void value(uint32_t tag, const char* name, int32_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
char buf[64];
snprintf(buf, 64, "%s - %d", name, value);
APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_EVENT,
OS_SIGNPOST_ID_EXCLUSIVE, name, buf)
}
}
inline void value(uint32_t tag, const char* name, int64_t value) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
char buf[64];
snprintf(buf, 64, "%s - %lld", name, value);
APPLE_SIGNPOST_EMIT(sGlobalState.systraceLog, OS_SIGNPOST_EVENT,
OS_SIGNPOST_ID_EXCLUSIVE, name, buf)
}
}
inline void frameId(uint32_t tag, uint32_t frame) noexcept {
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
char buf[64]; \
snprintf(buf, 64, "frame %u", frame); \
APPLE_SIGNPOST_EMIT(sGlobalState.frameIdLog, OS_SIGNPOST_EVENT,
OS_SIGNPOST_ID_EXCLUSIVE, "frame", buf)
}
}
private:
friend class ScopedTrace;
struct GlobalState {
std::atomic<uint32_t> isTracingEnabled;
os_log_t systraceLog;
os_log_t frameIdLog;
};
static GlobalState sGlobalState;
void init(uint32_t tag) noexcept;
// cached values for faster access, no need to be initialized
bool mIsTracingEnabled;
static void setup() noexcept;
static void init_once() noexcept;
static bool isTracingEnabled(uint32_t tag) noexcept;
};
// ------------------------------------------------------------------------------------------------
class ScopedTrace {
public:
// we don't inline this because it's relatively heavy due to a global check
ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mName(name), mTag(tag) {
mTrace.traceBegin(tag, name);
}
inline ~ScopedTrace() noexcept {
mTrace.traceEnd(mTag, mName);
}
inline void value(uint32_t tag, const char* name, int32_t v) noexcept {
mTrace.value(tag, name, v);
}
inline void value(uint32_t tag, const char* name, int64_t v) noexcept {
mTrace.value(tag, name, v);
}
private:
Systrace mTrace;
const char* mName;
const uint32_t mTag;
};
} // namespace details
} // namespace utils
#endif // TNT_UTILS_DARWIN_SYSTRACE_H

View File

@@ -17,8 +17,6 @@
#include <utils/Systrace.h>
#include <utils/Log.h>
#if defined(__ANDROID__)
#include <cinttypes>
#include <string.h>
@@ -219,5 +217,3 @@ void Systrace::int64_body(int fd, int pid, const char* name, int64_t value) noex
} // namespace details
} // namespace utils
#endif // ANDROID

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2023 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 <utils/Systrace.h>
#include <utils/Log.h>
#if FILAMENT_APPLE_SYSTRACE
#include <pthread.h>
static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
thread_local std::stack<const char*> ___tracerSections;
namespace utils {
namespace details {
Systrace::GlobalState Systrace::sGlobalState = {};
void Systrace::init_once() noexcept {
GlobalState& s = sGlobalState;
s.systraceLog = os_log_create("com.google.filament", "systrace");
s.frameIdLog = os_log_create("com.google.filament", "frameId");
}
void Systrace::setup() noexcept {
pthread_once(&atrace_once_control, init_once);
}
void Systrace::enable(uint32_t tags) noexcept {
setup();
sGlobalState.isTracingEnabled.fetch_or(tags, std::memory_order_relaxed);
}
void Systrace::disable(uint32_t tags) noexcept {
sGlobalState.isTracingEnabled.fetch_and(~tags, std::memory_order_relaxed);
}
// unfortunately, this generates quite a bit of code because reading a global is not
// trivial. For this reason, we do not inline this method.
bool Systrace::isTracingEnabled(uint32_t tag) noexcept {
if (tag) {
setup();
return bool((sGlobalState.isTracingEnabled.load(std::memory_order_relaxed) | SYSTRACE_TAG_ALWAYS) & tag);
}
return false;
}
// ------------------------------------------------------------------------------------------------
void Systrace::init(uint32_t tag) noexcept {
// must be called first
mIsTracingEnabled = isTracingEnabled(tag);
}
} // namespace details
} // namespace utils
#endif // FILAMENT_APPLE_SYSTRACE

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)

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.31.2",
"version": "1.31.3",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",