feat: update Filament to v1.56.4

This commit is contained in:
Nick Fisher
2025-01-07 08:27:19 +08:00
parent b1c0d4b2e8
commit 020bfbcbf6
60 changed files with 1772 additions and 21074 deletions

View File

@@ -278,18 +278,23 @@ public:
void* pop() noexcept {
Node* const pStorage = mStorage;
HeadPtr currentHead = mHead.load();
HeadPtr currentHead = mHead.load(std::memory_order_relaxed);
while (currentHead.offset >= 0) {
// The value of "pNext" we load here might already contain application data if another
// thread raced ahead of us. But in that case, the computed "newHead" will be discarded
// since compare_exchange_weak fails. Then this thread will loop with the updated
// since compare_exchange_weak() fails. Then this thread will loop with the updated
// value of currentHead, and try again.
Node* const pNext = pStorage[currentHead.offset].next.load(std::memory_order_relaxed);
// TSAN complains if we don't use a local variable here.
Node const node = pStorage[currentHead.offset];
Node const* const pNext = node.next;
const HeadPtr newHead{ pNext ? int32_t(pNext - pStorage) : -1, currentHead.tag + 1 };
// In the rare case that the other thread that raced ahead of us already returned the
// same mHead we just loaded, but it now has a different "next" value, the tag field will not
// match, and compare_exchange_weak will fail and prevent that particular race condition.
if (mHead.compare_exchange_weak(currentHead, newHead)) {
// In the rare case that the other thread that raced ahead of us already returned the
// same mHead we just loaded, but it now has a different "next" value, the tag field
// will not match, and compare_exchange_weak() will fail and prevent that particular
// race condition.
// acquire: no read/write can be reordered before this
if (mHead.compare_exchange_weak(currentHead, newHead,
std::memory_order_acquire, std::memory_order_relaxed)) {
// This assert needs to occur after we have validated that there was no race condition
// Otherwise, next might already contain application data, if another thread
// raced ahead of us after we loaded mHead, but before we loaded mHead->next.
@@ -306,13 +311,15 @@ public:
Node* const storage = mStorage;
assert_invariant(p && p >= storage);
Node* const node = static_cast<Node*>(p);
HeadPtr currentHead = mHead.load();
HeadPtr currentHead = mHead.load(std::memory_order_relaxed);
HeadPtr newHead = { int32_t(node - storage), currentHead.tag + 1 };
do {
newHead.tag = currentHead.tag + 1;
Node* const n = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr;
node->next.store(n, std::memory_order_relaxed);
} while(!mHead.compare_exchange_weak(currentHead, newHead));
Node* const pNext = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr;
node->next = pNext; // could be a race with pop, corrected by CAS
} while(!mHead.compare_exchange_weak(currentHead, newHead,
std::memory_order_release, std::memory_order_relaxed));
// release: no read/write can be reordered after this
}
void* getFirst() noexcept {
@@ -320,10 +327,7 @@ public:
}
struct Node {
// This should be a regular (non-atomic) pointer, but this causes TSAN to complain
// about a data-race that exists but is benin. We always use this atomic<> in
// relaxed mode.
// The data race TSAN complains about is when a pop() is interrupted by a
// There is a benign data race when a pop() is interrupted by a
// pop() + push() just after mHead->next is read -- it appears as though it is written
// without synchronization (by the push), however in that case, the pop's CAS will fail
// and things will auto-correct.
@@ -346,7 +350,7 @@ public:
// |
// CAS, tag++
//
std::atomic<Node*> next;
Node* next = nullptr;
};
private:

View File

@@ -84,7 +84,7 @@ public:
FixedCapacityVector() = default;
explicit FixedCapacityVector(const allocator_type& allocator) noexcept
: mCapacityAllocator({}, allocator) {
: mCapacityAllocator(0, allocator) {
}
explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type())
@@ -299,6 +299,16 @@ public:
}
}
UTILS_NOINLINE
void shrink_to_fit() {
if (size() < capacity()) {
FixedCapacityVector t(construct_with_capacity, size(), allocator());
t.mSize = size();
std::uninitialized_move(begin(), end(), t.begin());
this->swap(t);
}
}
private:
enum construct_with_capacity_tag{ construct_with_capacity };
@@ -318,9 +328,9 @@ private:
iterator assertCapacityForSize(size_type s) {
if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) {
ASSERT_PRECONDITION(capacity() >= s,
"capacity exceeded: requested size %lu, available capacity %lu.",
(unsigned long)s, (unsigned long)capacity());
FILAMENT_CHECK_PRECONDITION(capacity() >= s)
<< "capacity exceeded: requested size " << (unsigned long)s
<< "u, available capacity " << (unsigned long)capacity() << "u.";
}
return end();
}

View File

@@ -17,14 +17,28 @@
#ifndef TNT_UTILS_PANIC_H
#define TNT_UTILS_PANIC_H
#ifdef FILAMENT_PANIC_USES_ABSL
# if FILAMENT_PANIC_USES_ABSL
# include "absl/log/log.h"
# define FILAMENT_CHECK_PRECONDITION CHECK
# define FILAMENT_CHECK_POSTCONDITION CHECK
# define FILAMENT_CHECK_ARITHMETIC CHECK
# endif
#endif
#include <utils/CallStack.h>
#include <utils/compiler.h>
#include <utils/sstream.h>
#include <string>
#include <string_view>
#ifdef __EXCEPTIONS
# define UTILS_EXCEPTIONS 1
#else
# ifdef UTILS_EXCEPTIONS
# error UTILS_EXCEPTIONS is already defined!
# endif
#endif
/**
@@ -250,42 +264,83 @@ namespace utils {
*/
class UTILS_PUBLIC Panic {
public:
using PanicHandlerCallback = void(*)(void* user, Panic const& panic);
/**
* Sets a user-defined handler for the Panic. If exceptions are enabled, the concrete Panic
* object will be thrown upon return; moreover it is acceptable to throw from the provided
* callback, but it is unsafe to throw the Panic object itself, since it's just an interface.
* It is also acceptable to abort from the callback. If exceptions are not enabled, std::abort()
* will be automatically called upon return.
*
* The PanicHandlerCallback can be called from any thread.
*
* Caveat: this API can misbehave if is used as a static library in multiple translation units,
* some of these translation units might not see the callback.
*
* @param handler pointer to the user defined handler for the Panic
* @param user user pointer given back to the callback
*/
static void setPanicHandler(PanicHandlerCallback handler, void* user) noexcept;
virtual ~Panic() noexcept;
/**
* @return a detailed description of the error
* @return a formatted and detailed description of the error including all available
* information.
* @see std::exception
*/
virtual const char* what() const noexcept = 0;
/**
* Get the function name where the panic was detected
* Get the type of the panic (e.g. "Precondition")
* @return a C string containing the type of panic
*/
virtual const char* getType() const noexcept = 0;
/**
* Get the reason string for the panic
* @return a C string containing the reason for the panic
*/
virtual const char* getReason() const noexcept = 0;
/**
* Get a version of the reason string that is guaranteed to be constructed from literal
* strings only; it will contain no runtime information.
*/
virtual const char* getReasonLiteral() const noexcept = 0;
/**
* Get the function name where the panic was detected. On debug build the fully qualified
* function name is returned; on release builds only the function name is.
* @return a C string containing the function name where the panic was detected
*/
virtual const char* getFunction() const noexcept = 0;
/**
* Get the file name where the panic was detected
* Get the file name where the panic was detected. Only available on debug builds.
* @return a C string containing the file name where the panic was detected
*/
virtual const char* getFile() const noexcept = 0;
/**
* Get the line number in the file where the panic was detected
* Get the line number in the file where the panic was detected. Only available on debug builds.
* @return an integer containing the line number in the file where the panic was detected
*/
virtual int getLine() const noexcept = 0;
/**
* Logs this exception to the system-log
*/
virtual void log() const noexcept = 0;
/**
* Get the CallStack when the panic was detected
* Get the CallStack when the panic was detected if available.
* @return the CallStack when the panic was detected
*/
virtual const CallStack& getCallStack() const noexcept = 0;
/**
* Logs this exception to the system-log
*/
virtual void log() const noexcept = 0;
};
// -----------------------------------------------------------------------------------------------
@@ -305,6 +360,9 @@ public:
const char* what() const noexcept override;
// Panic interface
const char* getType() const noexcept override;
const char* getReason() const noexcept override;
const char* getReasonLiteral() const noexcept override;
const char* getFunction() const noexcept override;
const char* getFile() const noexcept override;
int getLine() const noexcept override;
@@ -318,13 +376,14 @@ public:
* @param function the name of the function where the error was detected
* @param file the file where the above function in implemented
* @param line the line in the above file where the error was detected
* @param literal a literal version of the error message
* @param format printf style string describing the error
* @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC
* @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC
* @see setMode()
*/
static void panic(char const* function, char const* file, int line, const char* format, ...)
UTILS_NORETURN;
static void panic(char const* function, char const* file, int line, char const* literal,
const char* format, ...) UTILS_NORETURN;
/**
* Depending on the mode set, either throws an exception of type T with the given reason plus
@@ -333,43 +392,41 @@ public:
* @param function the name of the function where the error was detected
* @param file the file where the above function in implemented
* @param line the line in the above file where the error was detected
* @param s std::string describing the error
* @param literal a literal version of the error message
* @param reason std::string describing the error
* @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC
* @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC
* @see setMode()
*/
static inline void panic(char const* function, char const* file, int line, const std::string& s)
UTILS_NORETURN {
panic(function, file, line, s.c_str());
}
static inline void panic(
char const* function, char const* file, int line, char const* literal,
std::string reason) UTILS_NORETURN;
protected:
/**
* Creates a Panic.
* @param reason a description of the cause of the error
*/
explicit TPanic(std::string reason);
/**
* Creates a Panic with extra information about the error-site.
* @param function the name of the function where the error was detected
* @param file the file where the above function in implemented
* @param line the line in the above file where the error was detected
* @param literal a literal version of the error message
* @param reason a description of the cause of the error
*/
TPanic(char const* function, char const* file, int line, std::string reason);
TPanic(char const* function, char const* file, int line, char const* literal,
std::string reason);
~TPanic() override;
private:
void buildMessage();
CallStack m_callstack;
std::string m_reason;
char const* const m_function = nullptr;
char const* const m_file = nullptr;
const int m_line = -1;
mutable std::string m_msg;
char const* const mFile = nullptr; // file where the panic happened
char const* const mFunction = nullptr; // function where the panic happened
int const mLine = -1; // line where the panic happened
std::string mLiteral; // reason for the panic, built only from literals
std::string mReason; // reason for the panic
mutable std::string mWhat; // fully formatted reason
CallStack mCallstack;
};
namespace details {
@@ -391,6 +448,7 @@ class UTILS_PUBLIC PreconditionPanic : public TPanic<PreconditionPanic> {
// e.g.: invalid arguments
using TPanic<PreconditionPanic>::TPanic;
friend class TPanic<PreconditionPanic>;
constexpr static auto type = "Precondition";
};
/**
@@ -404,6 +462,7 @@ class UTILS_PUBLIC PostconditionPanic : public TPanic<PostconditionPanic> {
// e.g.: dead-lock would occur, arithmetic errors
using TPanic<PostconditionPanic>::TPanic;
friend class TPanic<PostconditionPanic>;
constexpr static auto type = "Postcondition";
};
/**
@@ -417,8 +476,74 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
// e.g.: underflow, overflow, internal computations errors
using TPanic<ArithmeticPanic>::TPanic;
friend class TPanic<ArithmeticPanic>;
constexpr static auto type = "Arithmetic";
};
namespace details {
struct Voidify final {
template<typename T>
void operator&&(const T&) const&& {}
};
class UTILS_PUBLIC PanicStream {
public:
PanicStream(
char const* function,
char const* file,
int line,
char const* message) noexcept;
~PanicStream();
PanicStream& operator<<(short value) noexcept;
PanicStream& operator<<(unsigned short value) noexcept;
PanicStream& operator<<(char value) noexcept;
PanicStream& operator<<(unsigned char value) noexcept;
PanicStream& operator<<(int value) noexcept;
PanicStream& operator<<(unsigned int value) noexcept;
PanicStream& operator<<(long value) noexcept;
PanicStream& operator<<(unsigned long value) noexcept;
PanicStream& operator<<(long long value) noexcept;
PanicStream& operator<<(unsigned long long value) noexcept;
PanicStream& operator<<(float value) noexcept;
PanicStream& operator<<(double value) noexcept;
PanicStream& operator<<(long double value) noexcept;
PanicStream& operator<<(bool value) noexcept;
PanicStream& operator<<(const void* value) noexcept;
PanicStream& operator<<(const char* string) noexcept;
PanicStream& operator<<(const unsigned char* string) noexcept;
PanicStream& operator<<(std::string const& s) noexcept;
PanicStream& operator<<(std::string_view const& s) noexcept;
protected:
io::sstream mStream;
char const* mFunction;
char const* mFile;
int mLine;
char const* mLiteral;
};
template<typename T>
class TPanicStream : public PanicStream {
public:
using PanicStream::PanicStream;
~TPanicStream() noexcept(false) UTILS_NORETURN {
T::panic(mFunction, mFile, mLine, mLiteral, mStream.c_str());
}
};
} // namespace details
// -----------------------------------------------------------------------------------------------
} // namespace utils
@@ -430,37 +555,70 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
# define PANIC_FUNCTION __func__
#endif
#define FILAMENT_CHECK_CONDITION_IMPL(cond) \
switch (0) \
case 0: \
default: \
UTILS_LIKELY(cond) ? (void)0 : ::utils::details::Voidify()&&
#define FILAMENT_PANIC_IMPL(message, TYPE) \
::utils::details::TPanicStream<::utils::TYPE>(PANIC_FUNCTION, PANIC_FILE(__FILE__), __LINE__, message)
#ifndef FILAMENT_CHECK_PRECONDITION
#define FILAMENT_CHECK_PRECONDITION(condition) \
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_PANIC_IMPL(#condition, PreconditionPanic)
#endif
#ifndef FILAMENT_CHECK_POSTCONDITION
#define FILAMENT_CHECK_POSTCONDITION(condition) \
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_PANIC_IMPL(#condition, PostconditionPanic)
#endif
#ifndef FILAMENT_CHECK_ARITHMETIC
#define FILAMENT_CHECK_ARITHMETIC(condition) \
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_PANIC_IMPL(#condition, ArithmeticPanic)
#endif
#define PANIC_PRECONDITION_IMPL(cond, format, ...) \
::utils::PreconditionPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, #cond, format, ##__VA_ARGS__)
#define PANIC_POSTCONDITION_IMPL(cond, format, ...) \
::utils::PostconditionPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, #cond, format, ##__VA_ARGS__)
#define PANIC_ARITHMETIC_IMPL(cond, format, ...) \
::utils::ArithmeticPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, #cond, format, ##__VA_ARGS__)
#define PANIC_LOG_IMPL(cond, format, ...) \
::utils::details::panicLog(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
/**
* PANIC_PRECONDITION is a macro that reports a PreconditionPanic
* @param format printf-style string describing the error in more details
*/
#define PANIC_PRECONDITION(format, ...) \
::utils::PreconditionPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
#define PANIC_PRECONDITION(format, ...) PANIC_PRECONDITION_IMPL(format, format, ##__VA_ARGS__)
/**
* PANIC_POSTCONDITION is a macro that reports a PostconditionPanic
* @param format printf-style string describing the error in more details
*/
#define PANIC_POSTCONDITION(format, ...) \
::utils::PostconditionPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
#define PANIC_POSTCONDITION(format, ...) PANIC_POSTCONDITION_IMPL(format, format, ##__VA_ARGS__)
/**
* PANIC_ARITHMETIC is a macro that reports a ArithmeticPanic
* @param format printf-style string describing the error in more details
*/
#define PANIC_ARITHMETIC(format, ...) \
::utils::ArithmeticPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
#define PANIC_ARITHMETIC(format, ...) PANIC_ARITHMETIC_IMPL(format, format, ##__VA_ARGS__)
/**
* PANIC_LOG is a macro that logs a Panic, and continues as usual.
* @param format printf-style string describing the error in more details
*/
#define PANIC_LOG(format, ...) \
::utils::details::panicLog(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
#define PANIC_LOG(format, ...) PANIC_LOG_IMPL(format, format, ##__VA_ARGS__)
/**
* @ingroup errors
@@ -471,14 +629,14 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
* @param format printf-style string describing the error in more details
*/
#define ASSERT_PRECONDITION(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__) : (void)0)
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_PRECONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
#else
#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
#endif
@@ -499,14 +657,14 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
* @endcode
*/
#define ASSERT_POSTCONDITION(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION(format, ##__VA_ARGS__) : (void)0)
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_POSTCONDITION_IMPL(cond, format, ##__VA_ARGS__), false : true)
#else
#define ASSERT_POSTCONDITION_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
#endif
/**
@@ -527,14 +685,14 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
* @endcode
*/
#define ASSERT_ARITHMETIC(cond, format, ...) \
(!(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__) : (void)0)
(!(cond) ? PANIC_ARITHMETIC_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG)
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_ARITHMETIC_IMPL(cond, format, ##__VA_ARGS__), false : true)
#else
#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true)
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__), false : true)
#endif
/**
@@ -558,6 +716,7 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
* }
* @endcode
*/
#define ASSERT_DESTRUCTOR(cond, format, ...) (!(cond) ? PANIC_LOG(format, ##__VA_ARGS__) : (void)0)
#define ASSERT_DESTRUCTOR(cond, format, ...) \
(!UTILS_LIKELY(cond) ? PANIC_LOG_IMPL(cond, format, ##__VA_ARGS__) : (void)0)
#endif // TNT_UTILS_PANIC_H

View File

@@ -368,7 +368,7 @@ public:
size_t last = mSize++;
// Fold expression on the comma operator
([&]{
new(std::get<Indices>(mArrays) + last) Elements{std::get<Indices>(args)};
new(std::get<Indices>(mArrays) + last) Elements{std::get<Indices>(std::forward<Structure>(args))};
}() , ...);
}
@@ -513,7 +513,7 @@ public:
return (soa.elementAt<E>(i) = other);
}
UTILS_ALWAYS_INLINE Type const& operator = (Type&& other) noexcept {
return (soa.elementAt<E>(i) = other);
return (soa.elementAt<E>(i) = std::forward<Type>(other));
}
// comparisons
UTILS_ALWAYS_INLINE bool operator==(Type const& other) const {

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 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_SYSTRACE_H
#define TNT_UTILS_SYSTRACE_H
#define SYSTRACE_TAG_NEVER (0)
#define SYSTRACE_TAG_ALWAYS (1<<0)
#define SYSTRACE_TAG_FILAMENT (1<<1) // don't change, used in makefiles
#define SYSTRACE_TAG_JOBSYSTEM (1<<2)
/*
* 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.
*/
#ifndef SYSTRACE_TAG
#define SYSTRACE_TAG (SYSTRACE_TAG_ALWAYS)
#endif
// 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
#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()
#define SYSTRACE_ASYNC_BEGIN(name, cookie)
#define SYSTRACE_ASYNC_END(name, cookie)
#define SYSTRACE_VALUE32(name, val)
#define SYSTRACE_VALUE64(name, val)
#endif // ANDROID
#endif // TNT_UTILS_SYSTRACE_H

View File

@@ -22,6 +22,7 @@
#include <type_traits> // for std::enable_if
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
namespace utils {
@@ -43,9 +44,15 @@ constexpr inline T clz(T x) noexcept {
static_assert(sizeof(T) * CHAR_BIT <= 128, "details::clz() only support up to 128 bits");
x |= (x >> 1u);
x |= (x >> 2u);
x |= (x >> 4u);
x |= (x >> 8u);
x |= (x >> 16u);
if constexpr (sizeof(T) * CHAR_BIT >= 8) { // just to silence compiler warning
x |= (x >> 4u);
}
if constexpr (sizeof(T) * CHAR_BIT >= 16) { // just to silence compiler warning
x |= (x >> 8u);
}
if constexpr (sizeof(T) * CHAR_BIT >= 32) { // just to silence compiler warning
x |= (x >> 16u);
}
if constexpr (sizeof(T) * CHAR_BIT >= 64) { // just to silence compiler warning
x |= (x >> 32u);
}
@@ -67,11 +74,15 @@ constexpr inline T ctz(T x) noexcept {
x &= -x;
#endif
if (x) c--;
if (sizeof(T) * CHAR_BIT >= 64) {
if constexpr (sizeof(T) * CHAR_BIT >= 64) {
if (x & T(0x00000000FFFFFFFF)) c -= 32;
}
if (x & T(0x0000FFFF0000FFFF)) c -= 16;
if (x & T(0x00FF00FF00FF00FF)) c -= 8;
if constexpr (sizeof(T) * CHAR_BIT >= 32) {
if (x & T(0x0000FFFF0000FFFF)) c -= 16;
}
if constexpr (sizeof(T) * CHAR_BIT >= 16) {
if (x & T(0x00FF00FF00FF00FF)) c -= 8;
}
if (x & T(0x0F0F0F0F0F0F0F0F)) c -= 4;
if (x & T(0x3333333333333333)) c -= 2;
if (x & T(0x5555555555555555)) c -= 1;
@@ -80,6 +91,24 @@ constexpr inline T ctz(T x) noexcept {
} // namespace details
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE clz(unsigned char x) noexcept {
#if __has_builtin(__builtin_clz)
return __builtin_clz((unsigned int)x) - 24;
#else
return details::clz(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE clz(unsigned short x) noexcept {
#if __has_builtin(__builtin_clz)
return __builtin_clz((unsigned int)x) - 16;
#else
return details::clz(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE clz(unsigned int x) noexcept {
#if __has_builtin(__builtin_clz)
@@ -107,6 +136,24 @@ unsigned long long UTILS_ALWAYS_INLINE clz(unsigned long long x) noexcept {
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE ctz(unsigned char x) noexcept {
#if __has_builtin(__builtin_ctz)
return __builtin_ctz(x);
#else
return details::ctz(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE ctz(unsigned short x) noexcept {
#if __has_builtin(__builtin_ctz)
return __builtin_ctz(x);
#else
return details::ctz(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE ctz(unsigned int x) noexcept {
#if __has_builtin(__builtin_ctz)
@@ -134,6 +181,24 @@ unsigned long long UTILS_ALWAYS_INLINE ctz(unsigned long long x) noexcept {
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE popcount(unsigned char x) noexcept {
#if __has_builtin(__builtin_popcount)
return __builtin_popcount(x);
#else
return details::popcount(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE popcount(unsigned short x) noexcept {
#if __has_builtin(__builtin_popcount)
return __builtin_popcount(x);
#else
return details::popcount(x);
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
unsigned int UTILS_ALWAYS_INLINE popcount(unsigned int x) noexcept {
#if __has_builtin(__builtin_popcount)
@@ -161,11 +226,6 @@ unsigned long long UTILS_ALWAYS_INLINE popcount(unsigned long long x) noexcept {
#endif
}
constexpr inline UTILS_PUBLIC UTILS_PURE
uint8_t UTILS_ALWAYS_INLINE popcount(uint8_t x) noexcept {
return (uint8_t)popcount((unsigned int)x);
}
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value>>
constexpr inline UTILS_PUBLIC UTILS_PURE

View File

@@ -60,6 +60,11 @@ public:
std::fill(std::begin(storage), std::end(storage), 0);
}
template<typename U, typename = typename std::enable_if_t<N == 1, U>>
explicit bitset(U value) noexcept {
storage[0] = value;
}
T getBitsAt(size_t n) const noexcept {
assert_invariant(n<N);
return storage[n];
@@ -94,6 +99,8 @@ public:
size_t size() const noexcept { return N * BITS_PER_WORD; }
bool empty() const noexcept { return none(); }
bool test(size_t bit) const noexcept { return operator[](bit); }
void set(size_t b) noexcept {
@@ -117,11 +124,14 @@ public:
storage[b / BITS_PER_WORD] ^= T(1) << (b % BITS_PER_WORD);
}
void reset() noexcept {
std::fill(std::begin(storage), std::end(storage), 0);
}
void clear() noexcept {
reset();
}
bool operator[](size_t b) const noexcept {
assert_invariant(b / BITS_PER_WORD < N);
return bool(storage[b / BITS_PER_WORD] & (T(1) << (b % BITS_PER_WORD)));

View File

@@ -20,6 +20,7 @@
#include <utils/compiler.h>
namespace utils {
UTILS_PUBLIC
void panic(const char *func, const char * file, int line, const char *assertion) noexcept;
} // namespace filament

View File

@@ -1,123 +0,0 @@
/*
* Copyright (C) 2016 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_LINUX_CONDITION_H
#define TNT_UTILS_LINUX_CONDITION_H
#include <atomic>
#include <chrono>
#include <condition_variable> // for cv_status
#include <limits>
#include <mutex> // for unique_lock
#include <utils/linux/Mutex.h>
#include <time.h>
namespace utils {
/*
* A very simple condition variable class that can be used as an (almost) drop-in replacement
* for std::condition_variable (doesn't have the timed wait() though).
* It is very low overhead as most of it is inlined.
*/
class Condition {
public:
Condition() noexcept = default;
Condition(const Condition&) = delete;
Condition& operator=(const Condition&) = delete;
void notify_all() noexcept {
pulse(std::numeric_limits<int>::max());
}
void notify_one() noexcept {
pulse(1);
}
void notify_n(size_t n) noexcept {
if (n > 0) pulse(n);
}
void wait(std::unique_lock<Mutex>& lock) noexcept {
wait_until(lock.mutex(), false, nullptr);
}
template <class P>
void wait(std::unique_lock<Mutex>& lock, P predicate) {
while (!predicate()) {
wait(lock);
}
}
template<typename D>
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
const std::chrono::time_point<std::chrono::steady_clock, D>& timeout_time) noexcept {
// convert to nanoseconds
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
using sec_t = decltype(timespec::tv_sec);
using nsec_t = decltype(timespec::tv_nsec);
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
return wait_until(lock.mutex(), false, &ts);
}
template<typename D>
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
const std::chrono::time_point<std::chrono::system_clock, D>& timeout_time) noexcept {
// convert to nanoseconds
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
using sec_t = decltype(timespec::tv_sec);
using nsec_t = decltype(timespec::tv_nsec);
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
return wait_until(lock.mutex(), true, &ts);
}
template<typename C, typename D, typename P>
bool wait_until(std::unique_lock<Mutex>& lock,
const std::chrono::time_point<C, D>& timeout_time, P predicate) noexcept {
while (!predicate()) {
if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
return predicate();
}
}
return true;
}
template<typename R, typename Period>
std::cv_status wait_for(std::unique_lock<Mutex>& lock,
const std::chrono::duration<R, Period>& rel_time) noexcept {
return wait_until(lock, std::chrono::steady_clock::now() + rel_time);
}
template<typename R, typename Period, typename P>
bool wait_for(std::unique_lock<Mutex>& lock,
const std::chrono::duration<R, Period>& rel_time, P pred) noexcept {
return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
}
private:
std::atomic<uint32_t> mState = { 0 };
void pulse(int threadCount) noexcept;
std::cv_status wait_until(Mutex* lock,
bool realtimeClock, timespec* ts) noexcept;
};
} // namespace utils
#endif // TNT_UTILS_LINUX_CONDITION_H

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2016 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_LINUX_MUTEX_H
#define TNT_UTILS_LINUX_MUTEX_H
#include <utils/compiler.h>
#include <atomic>
#include <stdint.h>
namespace utils {
/*
* A very simple mutex class that can be used as an (almost) drop-in replacement
* for std::mutex.
* It is very low overhead as most of it is inlined.
*/
class Mutex {
public:
constexpr Mutex() noexcept = default;
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
void lock() noexcept {
uint32_t old_state = UNLOCKED;
if (UTILS_UNLIKELY(!mState.compare_exchange_strong(old_state,
LOCKED, std::memory_order_acquire, std::memory_order_relaxed))) {
wait();
}
}
void unlock() noexcept {
if (UTILS_UNLIKELY(mState.exchange(UNLOCKED, std::memory_order_release) == LOCKED_CONTENDED)) {
wake();
}
}
private:
enum {
UNLOCKED = 0, LOCKED = 1, LOCKED_CONTENDED = 2
};
std::atomic<uint32_t> mState = { UNLOCKED };
void wait() noexcept;
void wake() noexcept;
};
} // namespace utils
#endif // TNT_UTILS_LINUX_MUTEX_H

View File

@@ -40,7 +40,7 @@ inline void* aligned_alloc(size_t size, size_t align) noexcept {
#if defined(WIN32)
p = ::_aligned_malloc(size, align);
#else
::posix_memalign(&p, align, size);
(void) ::posix_memalign(&p, align, size);
#endif
return p;
}
@@ -73,8 +73,8 @@ public:
using const_pointer = const TYPE*;
using reference = TYPE&;
using const_reference = const TYPE&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using size_type = ::size_t;
using difference_type = ::ptrdiff_t;
using propagate_on_container_move_assignment = std::true_type;
using is_always_equal = std::true_type;

View File

@@ -95,11 +95,11 @@ protected:
size_t length() const noexcept;
private:
void reserve(size_t newSize) noexcept;
void reserve(size_t newCapacity) noexcept;
char* buffer = nullptr; // buffer address
char* curr = nullptr; // current pointer
size_t size = 0; // size remaining
size_t sizeRemaining = 0; // size remaining
size_t capacity = 0; // total capacity of the buffer
};

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2019 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_SSTREAM_H
#define TNT_UTILS_SSTREAM_H
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <stddef.h>
namespace utils::io {
class UTILS_PUBLIC sstream : public ostream {
public:
ostream& flush() noexcept override;
const char* c_str() const noexcept;
size_t length() const noexcept;
};
} // namespace utils::io
#endif // TNT_UTILS_SSTREAM_H