add missing Filament headers for Windows
This commit is contained in:
116
thermion_dart/native/include/filament/utils/BinaryTreeArray.h
Normal file
116
thermion_dart/native/include/filament/utils/BinaryTreeArray.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_BINARYTREEARRAY_H
|
||||
#define TNT_UTILS_BINARYTREEARRAY_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class BinaryTreeArray {
|
||||
|
||||
// Simple fixed capacity stack
|
||||
template<typename TYPE, size_t CAPACITY,
|
||||
typename = std::enable_if_t<std::is_trivial_v<TYPE>>>
|
||||
class stack {
|
||||
TYPE mElements[CAPACITY];
|
||||
size_t mSize = 0;
|
||||
public:
|
||||
bool empty() const noexcept { return mSize == 0; }
|
||||
void push(TYPE const& v) noexcept {
|
||||
assert(mSize < CAPACITY);
|
||||
mElements[mSize++] = v;
|
||||
}
|
||||
void pop() noexcept {
|
||||
assert(mSize > 0);
|
||||
--mSize;
|
||||
}
|
||||
const TYPE& back() const noexcept {
|
||||
return mElements[mSize - 1];
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static size_t count(size_t height) noexcept { return (1u << height) - 1; }
|
||||
static size_t left(size_t i, size_t /*height*/) noexcept { return i + 1; }
|
||||
static size_t right(size_t i, size_t height) noexcept {
|
||||
return i + (size_t(1) << (height - 1));
|
||||
}
|
||||
|
||||
// this builds the depth-first binary tree array top down (post-order)
|
||||
template<typename Leaf, typename Node>
|
||||
static void traverse(size_t height, Leaf leaf, Node node) noexcept {
|
||||
|
||||
struct TNode {
|
||||
uint32_t index;
|
||||
uint32_t col;
|
||||
uint32_t height;
|
||||
uint32_t next;
|
||||
|
||||
bool isLeaf() const noexcept { return height == 1; }
|
||||
size_t left() const noexcept { return BinaryTreeArray::left(index, height); }
|
||||
size_t right() const noexcept { return BinaryTreeArray::right(index, height); }
|
||||
};
|
||||
|
||||
stack<TNode, 16> stack;
|
||||
stack.push(TNode{ 0, 0, (uint32_t)height, (uint32_t)count(height) });
|
||||
|
||||
uint32_t prevLeft = 0;
|
||||
uint32_t prevRight = 0;
|
||||
uint32_t prevIndex = 0;
|
||||
while (!stack.empty()) {
|
||||
TNode const* const UTILS_RESTRICT curr = &stack.back();
|
||||
const bool isLeaf = curr->isLeaf();
|
||||
const uint32_t index = curr->index;
|
||||
const uint32_t l = (uint32_t)curr->left();
|
||||
const uint32_t r = (uint32_t)curr->right();
|
||||
|
||||
if (prevLeft == index || prevRight == index) {
|
||||
if (!isLeaf) {
|
||||
// the 'next' node of our left node's right descendants is our right child
|
||||
stack.push({ l, 2 * curr->col, curr->height - 1, r });
|
||||
}
|
||||
} else if (l == prevIndex) {
|
||||
if (!isLeaf) {
|
||||
// the 'next' node of our right child is our own 'next' sibling
|
||||
stack.push({ r, 2 * curr->col + 1, curr->height - 1, curr->next });
|
||||
}
|
||||
} else {
|
||||
if (!isLeaf) {
|
||||
node(index, l, r, curr->next);
|
||||
} else {
|
||||
leaf(index, curr->col, curr->next);
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
prevLeft = l;
|
||||
prevRight = r;
|
||||
prevIndex = index;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif //TNT_UTILS_BINARYTREEARRAY_H
|
||||
26
thermion_dart/native/include/filament/utils/Condition.h
Normal file
26
thermion_dart/native/include/filament/utils/Condition.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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_CONDITION_H
|
||||
#define TNT_UTILS_CONDITION_H
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <utils/linux/Condition.h>
|
||||
#else
|
||||
#include <utils/generic/Condition.h>
|
||||
#endif
|
||||
|
||||
#endif // TNT_UTILS_CONDITION_H
|
||||
92
thermion_dart/native/include/filament/utils/CountDownLatch.h
Normal file
92
thermion_dart/native/include/filament/utils/CountDownLatch.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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_COUNTDOWNLATCH_H
|
||||
#define TNT_UTILS_COUNTDOWNLATCH_H
|
||||
|
||||
// note: we use our version of mutex/condition to keep this public header STL free
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* A count down latch is used to block one or several threads until the latch is signaled
|
||||
* a certain number of times.
|
||||
*
|
||||
* Threads entering the latch are blocked until the latch is signaled enough times.
|
||||
*
|
||||
* @see CyclicBarrier
|
||||
*/
|
||||
class CountDownLatch {
|
||||
public:
|
||||
/**
|
||||
* Creates a count down latch with a specified count. The minimum useful value is 1.
|
||||
* @param count the latch counter initial value
|
||||
*/
|
||||
explicit CountDownLatch(size_t count) noexcept;
|
||||
~CountDownLatch() = default;
|
||||
|
||||
/**
|
||||
* Blocks until latch() is called \p count times.
|
||||
* @see CountDownLatch(size_t count)
|
||||
*/
|
||||
void await() noexcept;
|
||||
|
||||
/**
|
||||
* Releases threads blocked in await() when called \p count times. Calling latch() more than
|
||||
* \p count times has no effect.
|
||||
* @see reset()
|
||||
*/
|
||||
void latch() noexcept;
|
||||
|
||||
/**
|
||||
* Resets the count-down latch to the given value.
|
||||
*
|
||||
* @param new_count New latch count. A value of zero will immediately unblock all waiting
|
||||
* threads.
|
||||
*
|
||||
* @warning Use with caution. It's only safe to reset the latch count when you're sure
|
||||
* that no threads are waiting in await(). This can be guaranteed in various ways, for
|
||||
* instance, if you have a single thread calling await(), you could call reset() from that
|
||||
* thread, or you could use a CyclicBarrier to make sure all threads using the CountDownLatch
|
||||
* are at a known place (i.e.: not in await()) when reset() is called.
|
||||
*/
|
||||
void reset(size_t new_count) noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of times latch() has been called since construction or reset.
|
||||
* @see reset(), CountDownLatch(size_t count)
|
||||
*/
|
||||
size_t getCount() const noexcept;
|
||||
|
||||
CountDownLatch() = delete;
|
||||
CountDownLatch(const CountDownLatch&) = delete;
|
||||
CountDownLatch& operator=(const CountDownLatch&) = delete;
|
||||
|
||||
private:
|
||||
uint32_t m_initial_count;
|
||||
uint32_t m_remaining_count;
|
||||
mutable Mutex m_lock;
|
||||
mutable Condition m_cv;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_COUNTDOWNLATCH_H
|
||||
84
thermion_dart/native/include/filament/utils/CyclicBarrier.h
Normal file
84
thermion_dart/native/include/filament/utils/CyclicBarrier.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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_CYCLIC_BARRIER_H
|
||||
#define TNT_UTILS_CYCLIC_BARRIER_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// note: we use our version of mutex/condition to keep this public header STL free
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* A cyclic barrier is used to synchronize several threads to a particular execution point.
|
||||
*
|
||||
* Threads entering the barrier are halted until all threads reach the barrier.
|
||||
*
|
||||
* @see CountDownLatch
|
||||
*/
|
||||
class CyclicBarrier {
|
||||
public:
|
||||
/**
|
||||
* Creates a cyclic barrier with a specified number of threads to synchronize. The minimum
|
||||
* useful value is 2. A value of 0 is invalid and is silently changed to 1.
|
||||
* @param num_threads Number of threads to synchronize.
|
||||
*/
|
||||
explicit CyclicBarrier(size_t num_threads) noexcept;
|
||||
|
||||
/**
|
||||
* @return The number of thread that are synchronized.
|
||||
*/
|
||||
size_t getThreadCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return Number of threads currently waiting on the barrier.
|
||||
*/
|
||||
size_t getWaitingThreadCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Blocks until getThreadCount()-1 other threads reach await().
|
||||
*/
|
||||
void await() noexcept;
|
||||
|
||||
/**
|
||||
* Resets the cyclic barrier to its original state and releases all waiting threads.
|
||||
*/
|
||||
void reset() noexcept;
|
||||
|
||||
CyclicBarrier() = delete;
|
||||
CyclicBarrier(const CyclicBarrier&) = delete;
|
||||
CyclicBarrier& operator=(const CyclicBarrier&) = delete;
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
TRAP, RELEASE
|
||||
};
|
||||
|
||||
const size_t m_num_threads;
|
||||
mutable Mutex m_lock;
|
||||
mutable Condition m_cv;
|
||||
|
||||
State m_state = State::TRAP;
|
||||
size_t m_trapped_threads = 0;
|
||||
size_t m_released_threads = 0;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_CYCLIC_BARRIER_H
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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_FIXEDCIRCULARBUFFER_H
|
||||
#define TNT_UTILS_FIXEDCIRCULARBUFFER_H
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
class FixedCircularBuffer {
|
||||
public:
|
||||
explicit FixedCircularBuffer(size_t capacity)
|
||||
: mData(std::make_unique<T[]>(capacity)), mCapacity(capacity) {}
|
||||
|
||||
size_t size() const noexcept { return mSize; }
|
||||
size_t capacity() const noexcept { return mCapacity; }
|
||||
bool full() const noexcept { return mCapacity > 0 && mSize == mCapacity; }
|
||||
bool empty() const noexcept { return mSize == 0; }
|
||||
|
||||
/**
|
||||
* Push v into the buffer. If the buffer is already full, removes the oldest item and returns
|
||||
* it. If this buffer has no capacity, simply returns v.
|
||||
* @param v the new value to push into the buffer
|
||||
* @return if the buffer was full, the oldest value which was displaced
|
||||
*/
|
||||
std::optional<T> push(T v) noexcept {
|
||||
if (mCapacity == 0) {
|
||||
return v;
|
||||
}
|
||||
std::optional<T> displaced = full() ? pop() : std::optional<T>{};
|
||||
mData[mEnd] = v;
|
||||
mEnd = (mEnd + 1) % mCapacity;
|
||||
mSize++;
|
||||
return displaced;
|
||||
}
|
||||
|
||||
T pop() noexcept {
|
||||
assert_invariant(mSize > 0);
|
||||
T result = mData[mBegin];
|
||||
mBegin = (mBegin + 1) % mCapacity;
|
||||
mSize--;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<T[]> mData;
|
||||
|
||||
size_t mBegin = 0;
|
||||
size_t mEnd = 0;
|
||||
size_t mSize = 0;
|
||||
size_t mCapacity;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_FIXEDCIRCULARBUFFER_H
|
||||
110
thermion_dart/native/include/filament/utils/Hash.h
Normal file
110
thermion_dart/native/include/filament/utils/Hash.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_HASH_H
|
||||
#define TNT_UTILS_HASH_H
|
||||
|
||||
#include <functional> // for std::hash
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils::hash {
|
||||
|
||||
inline size_t combine(size_t lhs, size_t rhs) noexcept {
|
||||
std::pair<size_t, size_t> const p{ lhs, rhs };
|
||||
return std::hash<std::string_view>{}({ (char*)&p, sizeof(p) });
|
||||
}
|
||||
|
||||
// Hash function that takes an arbitrary swath of word-aligned data.
|
||||
inline uint32_t murmur3(const uint32_t* key, size_t wordCount, uint32_t seed) noexcept {
|
||||
uint32_t h = seed;
|
||||
size_t i = wordCount;
|
||||
do {
|
||||
uint32_t k = *key++;
|
||||
k *= 0xcc9e2d51u;
|
||||
k = (k << 15u) | (k >> 17u);
|
||||
k *= 0x1b873593u;
|
||||
h ^= k;
|
||||
h = (h << 13u) | (h >> 19u);
|
||||
h = (h * 5u) + 0xe6546b64u;
|
||||
} while (--i);
|
||||
h ^= wordCount;
|
||||
h ^= h >> 16u;
|
||||
h *= 0x85ebca6bu;
|
||||
h ^= h >> 13u;
|
||||
h *= 0xc2b2ae35u;
|
||||
h ^= h >> 16u;
|
||||
return h;
|
||||
}
|
||||
|
||||
// The hash yields the same result for a given byte sequence regardless of alignment.
|
||||
inline uint32_t murmurSlow(const uint8_t* key, size_t byteCount, uint32_t seed) noexcept {
|
||||
const size_t wordCount = (byteCount + 3) / 4;
|
||||
const uint8_t* const last = key + byteCount;
|
||||
|
||||
// The remainder is identical to murmur3() except an inner loop safely "reads" an entire word.
|
||||
uint32_t h = seed;
|
||||
size_t wc = wordCount;
|
||||
do {
|
||||
uint32_t k = 0;
|
||||
for (int i = 0; i < 4 && key < last; ++i, ++key) {
|
||||
k >>= 8;
|
||||
k |= uint32_t(*key) << 24;
|
||||
}
|
||||
k *= 0xcc9e2d51u;
|
||||
k = (k << 15u) | (k >> 17u);
|
||||
k *= 0x1b873593u;
|
||||
h ^= k;
|
||||
h = (h << 13u) | (h >> 19u);
|
||||
h = (h * 5u) + 0xe6546b64u;
|
||||
} while (--wc);
|
||||
h ^= wordCount;
|
||||
h ^= h >> 16u;
|
||||
h *= 0x85ebca6bu;
|
||||
h ^= h >> 13u;
|
||||
h *= 0xc2b2ae35u;
|
||||
h ^= h >> 16u;
|
||||
return h;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct MurmurHashFn {
|
||||
uint32_t operator()(const T& key) const noexcept {
|
||||
static_assert(0 == (sizeof(key) & 3u), "Hashing requires a size that is a multiple of 4.");
|
||||
return murmur3((const uint32_t*) &key, sizeof(key) / 4, 0);
|
||||
}
|
||||
};
|
||||
|
||||
// combines two hashes together
|
||||
template<class T>
|
||||
inline void combine(size_t& seed, const T& v) noexcept {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9u + (seed << 6u) + (seed >> 2u);
|
||||
}
|
||||
|
||||
// combines two hashes together, faster but less good
|
||||
template<class T>
|
||||
inline void combine_fast(size_t& seed, const T& v) noexcept {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) << 1u;
|
||||
}
|
||||
|
||||
} // namespace utils::hash
|
||||
|
||||
#endif // TNT_UTILS_HASH_H
|
||||
615
thermion_dart/native/include/filament/utils/JobSystem.h
Normal file
615
thermion_dart/native/include/filament/utils/JobSystem.h
Normal file
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* 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_JOBSYSTEM_H
|
||||
#define TNT_UTILS_JOBSYSTEM_H
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/architecture.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/memalign.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/WorkStealingDequeue.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class JobSystem {
|
||||
static constexpr size_t MAX_JOB_COUNT = 1 << 14; // 16384
|
||||
static constexpr uint32_t JOB_COUNT_MASK = MAX_JOB_COUNT - 1;
|
||||
static constexpr uint32_t WAITER_COUNT_SHIFT = 24;
|
||||
static_assert(MAX_JOB_COUNT <= 0x7FFE, "MAX_JOB_COUNT must be <= 0x7FFE");
|
||||
using WorkQueue = WorkStealingDequeue<uint16_t, MAX_JOB_COUNT>;
|
||||
using Mutex = utils::Mutex;
|
||||
using Condition = utils::Condition;
|
||||
|
||||
public:
|
||||
class Job;
|
||||
|
||||
using ThreadId = uint8_t;
|
||||
|
||||
using JobFunc = void(*)(void*, JobSystem&, Job*);
|
||||
|
||||
static constexpr ThreadId invalidThreadId = 0xff;
|
||||
|
||||
class alignas(CACHELINE_SIZE) Job {
|
||||
public:
|
||||
Job() noexcept {} /* = default; */ /* clang bug */ // NOLINT(modernize-use-equals-default,cppcoreguidelines-pro-type-member-init)
|
||||
Job(const Job&) = delete;
|
||||
Job(Job&&) = delete;
|
||||
|
||||
private:
|
||||
friend class JobSystem;
|
||||
|
||||
// Size is chosen so that we can store at least std::function<>
|
||||
// the alignas() qualifier ensures we're multiple of a cache-line.
|
||||
static constexpr size_t JOB_STORAGE_SIZE_BYTES =
|
||||
sizeof(std::function<void()>) > 48 ? sizeof(std::function<void()>) : 48;
|
||||
static constexpr size_t JOB_STORAGE_SIZE_WORDS =
|
||||
(JOB_STORAGE_SIZE_BYTES + sizeof(void*) - 1) / sizeof(void*);
|
||||
|
||||
// keep it first, so it's correctly aligned with all architectures
|
||||
// this is where we store the job's data, typically a std::function<>
|
||||
// v7 | v8
|
||||
void* storage[JOB_STORAGE_SIZE_WORDS]; // 48 | 48
|
||||
JobFunc function; // 4 | 8
|
||||
uint16_t parent; // 2 | 2
|
||||
mutable ThreadId id = invalidThreadId; // 1 | 1
|
||||
mutable std::atomic<uint8_t> refCount = { 1 }; // 1 | 1
|
||||
std::atomic<uint32_t> runningJobCount = { 1 }; // 4 | 4
|
||||
// 4 | 0 (padding)
|
||||
// 64 | 64
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
// on windows std::function<void()> is bigger and forces the whole structure to be larger
|
||||
static_assert(sizeof(Job) == 64);
|
||||
#endif
|
||||
|
||||
explicit JobSystem(size_t threadCount = 0, size_t adoptableThreadsCount = 1) noexcept;
|
||||
|
||||
~JobSystem();
|
||||
|
||||
// Make the current thread part of the thread pool.
|
||||
void adopt();
|
||||
|
||||
// Remove this adopted thread from the parent. This is intended to be used for
|
||||
// shutting down a JobSystem. In particular, this doesn't allow the parent to
|
||||
// adopt more thread.
|
||||
void emancipate();
|
||||
|
||||
|
||||
// If a parent is not specified when creating a job, that job will automatically take the
|
||||
// root job as a parent.
|
||||
// The root job is reset when waited on.
|
||||
Job* setRootJob(Job* job) noexcept { return mRootJob = job; }
|
||||
|
||||
// use setRootJob() instead
|
||||
UTILS_DEPRECATED
|
||||
Job* setMasterJob(Job* job) noexcept { return setRootJob(job); }
|
||||
|
||||
|
||||
Job* create(Job* parent, JobFunc func) noexcept;
|
||||
|
||||
// NOTE: All methods below must be called from the same thread and that thread must be
|
||||
// owned by JobSystem's thread pool.
|
||||
|
||||
/*
|
||||
* Job creation examples:
|
||||
* ----------------------
|
||||
*
|
||||
* struct Functor {
|
||||
* uintptr_t storage[6];
|
||||
* void operator()(JobSystem&, Jobsystem::Job*);
|
||||
* } functor;
|
||||
*
|
||||
* struct Foo {
|
||||
* uintptr_t storage[6];
|
||||
* void method(JobSystem&, Jobsystem::Job*);
|
||||
* } foo;
|
||||
*
|
||||
* Functor and Foo size muse be <= uintptr_t[6]
|
||||
*
|
||||
* createJob()
|
||||
* createJob(parent)
|
||||
* createJob<Foo, &Foo::method>(parent, &foo)
|
||||
* createJob<Foo, &Foo::method>(parent, foo)
|
||||
* createJob<Foo, &Foo::method>(parent, std::ref(foo))
|
||||
* createJob(parent, functor)
|
||||
* createJob(parent, std::ref(functor))
|
||||
* createJob(parent, [ up-to 6 uintptr_t ](JobSystem*, Jobsystem::Job*){ })
|
||||
*
|
||||
* Utility functions:
|
||||
* ------------------
|
||||
* These are less efficient, but handle any size objects using the heap if needed.
|
||||
* (internally uses std::function<>), and don't require the callee to take
|
||||
* a (JobSystem&, Jobsystem::Job*) as parameter.
|
||||
*
|
||||
* struct BigFoo {
|
||||
* uintptr_t large[16];
|
||||
* void operator()();
|
||||
* void method(int answerToEverything);
|
||||
* static void exec(BigFoo&) { }
|
||||
* } bigFoo;
|
||||
*
|
||||
* jobs::createJob(js, parent, [ any-capture ](int answerToEverything){}, 42);
|
||||
* jobs::createJob(js, parent, &BigFoo::method, &bigFoo, 42);
|
||||
* jobs::createJob(js, parent, &BigFoo::exec, std::ref(bigFoo));
|
||||
* jobs::createJob(js, parent, bigFoo);
|
||||
* jobs::createJob(js, parent, std::ref(bigFoo));
|
||||
* etc...
|
||||
*
|
||||
* struct SmallFunctor {
|
||||
* uintptr_t storage[3];
|
||||
* void operator()(T* data, size_t count);
|
||||
* } smallFunctor;
|
||||
*
|
||||
* jobs::parallel_for(js, data, count, [ up-to 3 uintptr_t ](T* data, size_t count) { });
|
||||
* jobs::parallel_for(js, data, count, smallFunctor);
|
||||
* jobs::parallel_for(js, data, count, std::ref(smallFunctor));
|
||||
*
|
||||
*/
|
||||
|
||||
// creates an empty (no-op) job with an optional parent
|
||||
Job* createJob(Job* parent = nullptr) noexcept {
|
||||
return create(parent, nullptr);
|
||||
}
|
||||
|
||||
// creates a job from a KNOWN method pointer w/ object passed by pointer
|
||||
// the caller must ensure the object will outlive the Job
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T* data) noexcept {
|
||||
Job* job = create(parent, +[](void* storage, JobSystem& js, Job* job) {
|
||||
T* const that = static_cast<T*>(reinterpret_cast<void**>(storage)[0]);
|
||||
(that->*method)(js, job);
|
||||
});
|
||||
if (job) {
|
||||
job->storage[0] = data;
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a KNOWN method pointer w/ object passed by value
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T data) noexcept {
|
||||
static_assert(sizeof(data) <= sizeof(Job::storage), "user data too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job) {
|
||||
T* const that = static_cast<T*>(storage);
|
||||
(that->*method)(js, job);
|
||||
that->~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::move(data));
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a KNOWN method pointer w/ object passed by value
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*), typename ... ARGS>
|
||||
Job* emplaceJob(Job* parent, ARGS&& ... args) noexcept {
|
||||
static_assert(sizeof(T) <= sizeof(Job::storage), "user data too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job) {
|
||||
T* const that = static_cast<T*>(storage);
|
||||
(that->*method)(js, job);
|
||||
that->~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::forward<ARGS>(args)...);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a functor passed by value
|
||||
template<typename T>
|
||||
Job* createJob(Job* parent, T functor) noexcept {
|
||||
static_assert(sizeof(functor) <= sizeof(Job::storage), "functor too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job){
|
||||
T* const that = static_cast<T*>(storage);
|
||||
that->operator()(js, job);
|
||||
that->~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::move(functor));
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a functor passed by value
|
||||
template<typename T, typename ... ARGS>
|
||||
Job* emplaceJob(Job* parent, ARGS&& ... args) noexcept {
|
||||
static_assert(sizeof(T) <= sizeof(Job::storage), "functor too large");
|
||||
Job* job = create(parent, [](void* storage, JobSystem& js, Job* job){
|
||||
T* const that = static_cast<T*>(storage);
|
||||
that->operator()(js, job);
|
||||
that->~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::forward<ARGS>(args)...);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Jobs are normally finished automatically, this can be used to cancel a job before it is run.
|
||||
*
|
||||
* Never use this once a flavor of run() has been called.
|
||||
*/
|
||||
void cancel(Job*& job) noexcept;
|
||||
|
||||
/*
|
||||
* Adds a reference to a Job.
|
||||
*
|
||||
* This allows the caller to waitAndRelease() on this job from multiple threads.
|
||||
* Use runAndWait() if waiting from multiple threads is not needed.
|
||||
*
|
||||
* This job MUST BE waited on with waitAndRelease(), or released with release().
|
||||
*/
|
||||
static Job* retain(Job* job) noexcept;
|
||||
|
||||
/*
|
||||
* Releases a reference from a Job obtained with runAndRetain() or a call to retain().
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void release(Job*& job) noexcept;
|
||||
void release(Job*&& job) noexcept {
|
||||
Job* p = job;
|
||||
release(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue. Its reference will drop automatically.
|
||||
* The current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void run(Job*& job) noexcept;
|
||||
void run(Job*&& job) noexcept { // allows run(createJob(...));
|
||||
Job* p = job;
|
||||
run(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue. Its reference will drop automatically.
|
||||
* The current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
* id must be the current thread id obtained with JobSystem::getThreadId(Job*). This
|
||||
* API is more efficient than the methods above.
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void run(Job*& job, ThreadId id) noexcept;
|
||||
void run(Job*&& job, ThreadId id) noexcept { // allows run(createJob(...));
|
||||
Job* p = job;
|
||||
run(p, id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue and keep a reference to it.
|
||||
* The current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* This job MUST BE waited on with wait(), or released with release().
|
||||
*/
|
||||
Job* runAndRetain(Job* job) noexcept;
|
||||
|
||||
/*
|
||||
* Wait on a job and destroys it.
|
||||
* The current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* The job must first be obtained from runAndRetain() or retain().
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void waitAndRelease(Job*& job) noexcept;
|
||||
|
||||
/*
|
||||
* Runs and wait for a job. This is equivalent to calling
|
||||
* runAndRetain(job);
|
||||
* wait(job);
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void runAndWait(Job*& job) noexcept;
|
||||
void runAndWait(Job*&& job) noexcept { // allows runAndWait(createJob(...));
|
||||
Job* p = job;
|
||||
runAndWait(p);
|
||||
}
|
||||
|
||||
// for debugging
|
||||
friend io::ostream& operator << (io::ostream& out, JobSystem const& js);
|
||||
|
||||
|
||||
// utility functions...
|
||||
|
||||
// set the name of the current thread (on OSes that support it)
|
||||
static void setThreadName(const char* threadName) noexcept;
|
||||
|
||||
enum class Priority {
|
||||
NORMAL,
|
||||
DISPLAY,
|
||||
URGENT_DISPLAY,
|
||||
BACKGROUND
|
||||
};
|
||||
|
||||
static void setThreadPriority(Priority priority) noexcept;
|
||||
static void setThreadAffinityById(size_t id) noexcept;
|
||||
|
||||
size_t getParallelSplitCount() const noexcept {
|
||||
return mParallelSplitCount;
|
||||
}
|
||||
|
||||
size_t getThreadCount() const { return mThreadCount; }
|
||||
|
||||
// returns the current ThreadId, which can be used with run(). This method can only be
|
||||
// called from a job's function.
|
||||
static ThreadId getThreadId(Job const* job) noexcept {
|
||||
assert_invariant(job->id != invalidThreadId);
|
||||
return job->id;
|
||||
}
|
||||
|
||||
private:
|
||||
// this is just to avoid using std::default_random_engine, since we're in a public header.
|
||||
class default_random_engine {
|
||||
static constexpr uint32_t m = 0x7fffffffu;
|
||||
uint32_t mState; // must be 0 < seed < 0x7fffffff
|
||||
public:
|
||||
using result_type = uint32_t;
|
||||
|
||||
static constexpr result_type min() noexcept {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static constexpr result_type max() noexcept {
|
||||
return m - 1;
|
||||
}
|
||||
|
||||
inline constexpr explicit default_random_engine(uint32_t seed = 1u) noexcept
|
||||
: mState(((seed % m) == 0u) ? 1u : seed % m) {
|
||||
}
|
||||
inline uint32_t operator()() noexcept {
|
||||
return mState = uint32_t((uint64_t(mState) * 48271u) % m);
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(CACHELINE_SIZE) ThreadState { // this causes 40-bytes padding
|
||||
// make sure storage is cache-line aligned
|
||||
WorkQueue workQueue;
|
||||
|
||||
// these are not accessed by the worker threads
|
||||
alignas(CACHELINE_SIZE) // this causes 56-bytes padding
|
||||
JobSystem* js; // this is in fact const and always initialized
|
||||
std::thread thread; // unused for adopted threads
|
||||
default_random_engine rndGen;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ThreadState) % CACHELINE_SIZE == 0,
|
||||
"ThreadState doesn't align to a cache line");
|
||||
|
||||
ThreadState& getState() noexcept;
|
||||
|
||||
static void incRef(Job const* job) noexcept;
|
||||
void decRef(Job const* job) noexcept;
|
||||
|
||||
Job* allocateJob() noexcept;
|
||||
ThreadState* getStateToStealFrom(ThreadState& state) noexcept;
|
||||
static bool hasJobCompleted(Job const* job) noexcept;
|
||||
|
||||
void requestExit() noexcept;
|
||||
bool exitRequested() const noexcept;
|
||||
bool hasActiveJobs() const noexcept;
|
||||
|
||||
void loop(ThreadState* state) noexcept;
|
||||
bool execute(ThreadState& state) noexcept;
|
||||
Job* steal(ThreadState& state) noexcept;
|
||||
void finish(Job* job) noexcept;
|
||||
|
||||
void put(WorkQueue& workQueue, Job* job) noexcept;
|
||||
Job* pop(WorkQueue& workQueue) noexcept;
|
||||
Job* steal(WorkQueue& workQueue) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
uint32_t wait(std::unique_lock<Mutex>& lock, Job* job) noexcept;
|
||||
void wait(std::unique_lock<Mutex>& lock) noexcept;
|
||||
void wakeAll() noexcept;
|
||||
void wakeOne() noexcept;
|
||||
|
||||
// these have thread contention, keep them together
|
||||
Mutex mWaiterLock;
|
||||
Condition mWaiterCondition;
|
||||
|
||||
std::atomic<int32_t> mActiveJobs = { 0 };
|
||||
Arena<ObjectPoolAllocator<Job>, LockingPolicy::Mutex> mJobPool;
|
||||
|
||||
template <typename T>
|
||||
using aligned_vector = std::vector<T, STLAlignedAllocator<T>>;
|
||||
|
||||
// These are essentially const, make sure they're on a different cache-lines than the
|
||||
// read-write atomics.
|
||||
// We can't use "alignas(CACHELINE_SIZE)" because the standard allocator can't make this
|
||||
// guarantee.
|
||||
char padding[CACHELINE_SIZE];
|
||||
|
||||
alignas(16) // at least we align to half (or quarter) cache-line
|
||||
aligned_vector<ThreadState> mThreadStates; // actual data is stored offline
|
||||
std::atomic<bool> mExitRequested = { false }; // this one is almost never written
|
||||
std::atomic<uint16_t> mAdoptedThreads = { 0 }; // this one is almost never written
|
||||
Job* const mJobStorageBase; // Base for conversion to indices
|
||||
uint16_t mThreadCount = 0; // total # of threads in the pool
|
||||
uint8_t mParallelSplitCount = 0; // # of split allowable in parallel_for
|
||||
Job* mRootJob = nullptr;
|
||||
|
||||
Mutex mThreadMapLock; // this should have very little contention
|
||||
tsl::robin_map<std::thread::id, ThreadState *> mThreadMap;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Utility functions built on top of JobSystem
|
||||
|
||||
namespace jobs {
|
||||
|
||||
// These are convenience C++11 style job creation methods that support lambdas
|
||||
//
|
||||
// IMPORTANT: these are less efficient to call and may perform heap allocation
|
||||
// depending on the capture and parameters
|
||||
//
|
||||
template<typename CALLABLE, typename ... ARGS>
|
||||
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||
CALLABLE&& func, ARGS&&... args) noexcept {
|
||||
struct Data {
|
||||
explicit Data(std::function<void()> f) noexcept: f(std::move(f)) {}
|
||||
std::function<void()> f;
|
||||
// Renaming the method below could cause an Arrested Development.
|
||||
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||
};
|
||||
return js.emplaceJob<Data, &Data::gob>(parent,
|
||||
std::bind(std::forward<CALLABLE>(func), std::forward<ARGS>(args)...));
|
||||
}
|
||||
|
||||
template<typename CALLABLE, typename T, typename ... ARGS,
|
||||
typename = std::enable_if_t<
|
||||
std::is_member_function_pointer_v<std::remove_reference_t<CALLABLE>>
|
||||
>
|
||||
>
|
||||
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||
CALLABLE&& func, T&& o, ARGS&&... args) noexcept {
|
||||
struct Data {
|
||||
explicit Data(std::function<void()> f) noexcept: f(std::move(f)) {}
|
||||
std::function<void()> f;
|
||||
// Renaming the method below could cause an Arrested Development.
|
||||
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||
};
|
||||
return js.emplaceJob<Data, &Data::gob>(parent,
|
||||
std::bind(std::forward<CALLABLE>(func), std::forward<T>(o), std::forward<ARGS>(args)...));
|
||||
}
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename S, typename F>
|
||||
struct ParallelForJobData {
|
||||
using SplitterType = S;
|
||||
using Functor = F;
|
||||
using JobData = ParallelForJobData;
|
||||
using size_type = uint32_t;
|
||||
|
||||
ParallelForJobData(size_type start, size_type count, uint8_t splits,
|
||||
Functor functor,
|
||||
const SplitterType& splitter) noexcept
|
||||
: start(start), count(count),
|
||||
functor(std::move(functor)),
|
||||
splits(splits),
|
||||
splitter(splitter) {
|
||||
}
|
||||
|
||||
void parallelWithJobs(JobSystem& js, JobSystem::Job* parent) noexcept {
|
||||
assert(parent);
|
||||
|
||||
// this branch is often miss-predicted (it both sides happen 50% of the calls)
|
||||
right_side:
|
||||
if (splitter.split(splits, count)) {
|
||||
const size_type lc = count / 2;
|
||||
JobSystem::Job* l = js.emplaceJob<JobData, &JobData::parallelWithJobs>(parent,
|
||||
start, lc, splits + uint8_t(1), functor, splitter);
|
||||
if (UTILS_UNLIKELY(l == nullptr)) {
|
||||
// couldn't create a job, just pretend we're done splitting
|
||||
goto execute;
|
||||
}
|
||||
|
||||
// start the left side before attempting the right side, so we parallelize in case
|
||||
// of job creation failure -- rare, but still.
|
||||
js.run(l, JobSystem::getThreadId(parent));
|
||||
|
||||
// don't spawn a job for the right side, just reuse us -- spawning jobs is more
|
||||
// costly than we'd like.
|
||||
start += lc;
|
||||
count -= lc;
|
||||
++splits;
|
||||
goto right_side;
|
||||
|
||||
} else {
|
||||
execute:
|
||||
// we're done splitting, do the real work here!
|
||||
functor(start, count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_type start; // 4
|
||||
size_type count; // 4
|
||||
Functor functor; // ?
|
||||
uint8_t splits; // 1
|
||||
SplitterType splitter; // 1
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
// parallel jobs with start/count indices
|
||||
template<typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
uint32_t start, uint32_t count, F functor, const S& splitter) noexcept {
|
||||
using JobData = details::ParallelForJobData<S, F>;
|
||||
return js.emplaceJob<JobData, &JobData::parallelWithJobs>(parent,
|
||||
start, count, 0, std::move(functor), splitter);
|
||||
}
|
||||
|
||||
// parallel jobs with pointer/count
|
||||
template<typename T, typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
T* data, uint32_t count, F functor, const S& splitter) noexcept {
|
||||
auto user = [data, f = std::move(functor)](uint32_t s, uint32_t c) {
|
||||
f(data + s, c);
|
||||
};
|
||||
using JobData = details::ParallelForJobData<S, decltype(user)>;
|
||||
return js.emplaceJob<JobData, &JobData::parallelWithJobs>(parent,
|
||||
0, count, 0, std::move(user), splitter);
|
||||
}
|
||||
|
||||
// parallel jobs on a Slice<>
|
||||
template<typename T, typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
Slice<T> slice, F functor, const S& splitter) noexcept {
|
||||
return parallel_for(js, parent, slice.data(), slice.size(), functor, splitter);
|
||||
}
|
||||
|
||||
|
||||
template<size_t COUNT, size_t MAX_SPLITS = 12>
|
||||
class CountSplitter {
|
||||
public:
|
||||
bool split(size_t splits, size_t count) const noexcept {
|
||||
return (splits < MAX_SPLITS && count >= COUNT * 2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jobs
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_JOBSYSTEM_H
|
||||
215
thermion_dart/native/include/filament/utils/Profiler.h
Normal file
215
thermion_dart/native/include/filament/utils/Profiler.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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_PROFILER_H
|
||||
#define TNT_UTILS_PROFILER_H
|
||||
|
||||
#include <ratio>
|
||||
#include <chrono> // note: This is safe (only used inline)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <unistd.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <linux/perf_event.h>
|
||||
#endif
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class Profiler {
|
||||
public:
|
||||
enum {
|
||||
INSTRUCTIONS = 0, // must be zero
|
||||
CPU_CYCLES = 1,
|
||||
DCACHE_REFS = 2,
|
||||
DCACHE_MISSES = 3,
|
||||
BRANCHES = 4,
|
||||
BRANCH_MISSES = 5,
|
||||
ICACHE_REFS = 6,
|
||||
ICACHE_MISSES = 7,
|
||||
|
||||
// Must be last one
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
EV_CPU_CYCLES = 1u << CPU_CYCLES,
|
||||
EV_L1D_REFS = 1u << DCACHE_REFS,
|
||||
EV_L1D_MISSES = 1u << DCACHE_MISSES,
|
||||
EV_BPU_REFS = 1u << BRANCHES,
|
||||
EV_BPU_MISSES = 1u << BRANCH_MISSES,
|
||||
EV_L1I_REFS = 1u << ICACHE_REFS,
|
||||
EV_L1I_MISSES = 1u << ICACHE_MISSES,
|
||||
// helpers
|
||||
EV_L1D_RATES = EV_L1D_REFS | EV_L1D_MISSES,
|
||||
EV_L1I_RATES = EV_L1I_REFS | EV_L1I_MISSES,
|
||||
EV_BPU_RATES = EV_BPU_REFS | EV_BPU_MISSES,
|
||||
};
|
||||
|
||||
Profiler() noexcept; // must call resetEvents()
|
||||
explicit Profiler(uint32_t eventMask) noexcept;
|
||||
~Profiler() noexcept;
|
||||
|
||||
Profiler(const Profiler& rhs) = delete;
|
||||
Profiler(Profiler&& rhs) = delete;
|
||||
Profiler& operator=(const Profiler& rhs) = delete;
|
||||
Profiler& operator=(Profiler&& rhs) = delete;
|
||||
|
||||
// selects which events are enabled.
|
||||
uint32_t resetEvents(uint32_t eventMask) noexcept;
|
||||
|
||||
uint32_t getEnabledEvents() const noexcept { return mEnabledEvents; }
|
||||
|
||||
// could return false if performance counters are not supported/enabled
|
||||
bool isValid() const { return mCountersFd[0] >= 0; }
|
||||
|
||||
class Counters {
|
||||
friend class Profiler;
|
||||
|
||||
uint64_t nr;
|
||||
uint64_t time_enabled;
|
||||
uint64_t time_running;
|
||||
struct {
|
||||
uint64_t value;
|
||||
uint64_t id;
|
||||
} counters[EVENT_COUNT];
|
||||
|
||||
friend Counters operator-(Counters lhs, const Counters& rhs) noexcept {
|
||||
lhs.nr -= rhs.nr;
|
||||
lhs.time_enabled -= rhs.time_enabled;
|
||||
lhs.time_running -= rhs.time_running;
|
||||
for (size_t i = 0; i < EVENT_COUNT; ++i) {
|
||||
lhs.counters[i].value -= rhs.counters[i].value;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
public:
|
||||
uint64_t getInstructions() const { return counters[INSTRUCTIONS].value; }
|
||||
uint64_t getCpuCycles() const { return counters[CPU_CYCLES].value; }
|
||||
uint64_t getL1DReferences() const { return counters[DCACHE_REFS].value; }
|
||||
uint64_t getL1DMisses() const { return counters[DCACHE_MISSES].value; }
|
||||
uint64_t getL1IReferences() const { return counters[ICACHE_REFS].value; }
|
||||
uint64_t getL1IMisses() const { return counters[ICACHE_MISSES].value; }
|
||||
uint64_t getBranchInstructions() const { return counters[BRANCHES].value; }
|
||||
uint64_t getBranchMisses() const { return counters[BRANCH_MISSES].value; }
|
||||
|
||||
std::chrono::duration<uint64_t, std::nano> getWallTime() const {
|
||||
return std::chrono::duration<uint64_t, std::nano>(time_enabled);
|
||||
}
|
||||
|
||||
std::chrono::duration<uint64_t, std::nano> getRunningTime() const {
|
||||
return std::chrono::duration<uint64_t, std::nano>(time_running);
|
||||
}
|
||||
|
||||
double getIPC() const noexcept {
|
||||
uint64_t cpuCycles = getCpuCycles();
|
||||
uint64_t instructions = getInstructions();
|
||||
return double(instructions) / double(cpuCycles);
|
||||
}
|
||||
|
||||
double getCPI() const noexcept {
|
||||
uint64_t cpuCycles = getCpuCycles();
|
||||
uint64_t instructions = getInstructions();
|
||||
return double(cpuCycles) / double(instructions);
|
||||
}
|
||||
|
||||
double getL1DMissRate() const noexcept {
|
||||
uint64_t cacheReferences = getL1DReferences();
|
||||
uint64_t cacheMisses = getL1DMisses();
|
||||
return double(cacheMisses) / double(cacheReferences);
|
||||
}
|
||||
|
||||
double getL1DHitRate() const noexcept {
|
||||
return 1.0 - getL1DMissRate();
|
||||
}
|
||||
|
||||
double getL1IMissRate() const noexcept {
|
||||
uint64_t cacheReferences = getL1IReferences();
|
||||
uint64_t cacheMisses = getL1IMisses();
|
||||
return double(cacheMisses) / double(cacheReferences);
|
||||
}
|
||||
|
||||
double getL1IHitRate() const noexcept {
|
||||
return 1.0 - getL1IMissRate();
|
||||
}
|
||||
|
||||
double getBranchMissRate() const noexcept {
|
||||
uint64_t branchReferences = getBranchInstructions();
|
||||
uint64_t branchMisses = getBranchMisses();
|
||||
return double(branchMisses) / double(branchReferences);
|
||||
}
|
||||
|
||||
double getBranchHitRate() const noexcept {
|
||||
return 1.0 - getBranchMissRate();
|
||||
}
|
||||
|
||||
double getMPKI(uint64_t misses) const noexcept {
|
||||
return (misses * 1000.0) / getInstructions();
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
void reset() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
void start() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
void stop() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
Counters readCounters() noexcept;
|
||||
|
||||
#else // !__linux__
|
||||
|
||||
void reset() noexcept { }
|
||||
void start() noexcept { }
|
||||
void stop() noexcept { }
|
||||
Counters readCounters() noexcept { return {}; }
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
bool hasBranchRates() const noexcept {
|
||||
return (mCountersFd[BRANCHES] >= 0) && (mCountersFd[BRANCH_MISSES] >= 0);
|
||||
}
|
||||
|
||||
bool hasICacheRates() const noexcept {
|
||||
return (mCountersFd[ICACHE_REFS] >= 0) && (mCountersFd[ICACHE_MISSES] >= 0);
|
||||
}
|
||||
|
||||
private:
|
||||
UTILS_UNUSED uint8_t mIds[EVENT_COUNT] = {};
|
||||
int mCountersFd[EVENT_COUNT];
|
||||
uint32_t mEnabledEvents = 0;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_PROFILER_H
|
||||
185
thermion_dart/native/include/filament/utils/QuadTree.h
Normal file
185
thermion_dart/native/include/filament/utils/QuadTree.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_QUADTREE_H
|
||||
#define TNT_UTILS_QUADTREE_H
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
namespace QuadTreeUtils {
|
||||
|
||||
/**
|
||||
* 16-bits morton encoding
|
||||
* @param x 8-bits horizontal coordinate
|
||||
* @param y 8-bits vertical coordinate
|
||||
* @return morton encoding of (x,y)
|
||||
*/
|
||||
static inline constexpr uint16_t morton(uint8_t x, uint8_t y) noexcept {
|
||||
uint32_t r = x | (uint32_t(y) << 16);
|
||||
r = (r | (r << 4u)) & 0x0f0f0f0fu;
|
||||
r = (r | (r << 2u)) & 0x33333333u;
|
||||
r = (r | (r << 1u)) & 0x55555555u;
|
||||
return uint16_t(r | (r >> 15u));
|
||||
}
|
||||
|
||||
/**
|
||||
* size of a quad-tree of height `height`
|
||||
* @param height height of the Quad-tree
|
||||
* @return the number of elements in the tree
|
||||
*/
|
||||
static inline constexpr size_t size(size_t height) noexcept {
|
||||
return morton(uint8_t((1u << height) - 1u), 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index in the QuadTreeArray of a Quad-tree node referenced by its height and code
|
||||
* @param l height of the node
|
||||
* @param code morton code of the node
|
||||
* @return index in the QuadTreeArray of this node
|
||||
*/
|
||||
static inline constexpr size_t index(size_t l, size_t code) noexcept {
|
||||
return size(l) + code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Index in the QuadTreeArray of the parent of the specified node
|
||||
* @param l height of the node
|
||||
* @param code morton code of the node
|
||||
* @return index in the QuadTreeArray of this node's parent
|
||||
*/
|
||||
static inline constexpr size_t parent(size_t l, size_t code) noexcept {
|
||||
assert_invariant(l > 0);
|
||||
return index(l - 1u, code >> 2u);
|
||||
}
|
||||
|
||||
// integrated unit-tests!
|
||||
static_assert(size(0) == 0);
|
||||
static_assert(size(1) == 1);
|
||||
static_assert(size(2) == 5);
|
||||
static_assert(size(3) == 21);
|
||||
static_assert(size(4) == 85);
|
||||
static_assert(size(5) == 341);
|
||||
static_assert(size(6) == 1365);
|
||||
static_assert(size(7) == 5461);
|
||||
|
||||
} // namespace QuadTreeUtils
|
||||
|
||||
/**
|
||||
* A Quad-tree encoded as an array.
|
||||
* @tparam T Type of the quad-tree nodes
|
||||
* @tparam HEIGHT Height of the quad-tree
|
||||
*/
|
||||
template<typename T, size_t HEIGHT>
|
||||
class QuadTreeArray : public std::array<T, QuadTreeUtils::size(HEIGHT)> {
|
||||
static_assert(HEIGHT <= 7, "QuadTreeArray height must be <= 7 (16-bits morton)");
|
||||
|
||||
// Simple fixed capacity stack
|
||||
template<typename TYPE, size_t CAPACITY,
|
||||
typename = std::enable_if_t<std::is_trivial_v<TYPE>>>
|
||||
class stack {
|
||||
TYPE mElements[CAPACITY];
|
||||
size_t mSize = 0;
|
||||
public:
|
||||
bool empty() const noexcept { return mSize == 0; }
|
||||
void push(TYPE const& v) noexcept {
|
||||
assert_invariant(mSize < CAPACITY);
|
||||
mElements[mSize++] = v;
|
||||
}
|
||||
void pop() noexcept {
|
||||
assert_invariant(mSize > 0);
|
||||
--mSize;
|
||||
}
|
||||
const TYPE& back() const noexcept {
|
||||
return mElements[mSize - 1];
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
// code_t needs to be able to encode the # of entries for the largest level supported
|
||||
// the tree. With 7 levels, the largest one as 4096 entries, 0 to 4095 so 12 bits suffice.
|
||||
using code_t = uint16_t;
|
||||
|
||||
struct NodeId {
|
||||
int8_t l : 4; // height of the node or -1 if invalid
|
||||
code_t code : 12; // morton code of the node
|
||||
static_assert(12 >= (HEIGHT - 1) * 2);
|
||||
};
|
||||
|
||||
enum class TraversalResult {
|
||||
EXIT, // end traversal
|
||||
RECURSE, // proceed with the children
|
||||
SKIP_CHILDREN // skip children
|
||||
};
|
||||
|
||||
static inline constexpr size_t height() noexcept {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
/**
|
||||
* non-recursive depth-first traversal
|
||||
*
|
||||
* @tparam Process closure to process each visited node
|
||||
* @param l height of the node to start with
|
||||
* @param code code of the node to start with
|
||||
* @param h maximum height to visit, must be < height()
|
||||
* @param process closure to process each visited node
|
||||
*/
|
||||
template<typename Process,
|
||||
typename = std::enable_if_t<
|
||||
std::is_invocable_r_v<TraversalResult, Process, NodeId>>>
|
||||
static void traverse(int8_t l, code_t code, size_t maxHeight, Process&& process) noexcept {
|
||||
assert_invariant(maxHeight < height());
|
||||
const int8_t h = int8_t(maxHeight);
|
||||
stack<NodeId, 4 * height()> stack;
|
||||
stack.push({ l, code });
|
||||
while (!stack.empty()) {
|
||||
NodeId curr = stack.back();
|
||||
stack.pop();
|
||||
TraversalResult r = process(curr);
|
||||
if (r == TraversalResult::EXIT) {
|
||||
break;
|
||||
}
|
||||
if (r == TraversalResult::RECURSE && curr.l < h) {
|
||||
for (size_t c = 0; c < 4; c++) {
|
||||
stack.push({
|
||||
int8_t(curr.l + 1u),
|
||||
code_t((curr.code << 2u) | (3u - c))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Node,
|
||||
typename = std::enable_if_t<
|
||||
std::is_invocable_r_v<TraversalResult, Node, NodeId>>>
|
||||
static void traverse(int8_t l, code_t code, Node&& process) noexcept {
|
||||
traverse(l, code, height() - 1, std::forward<Node>(process));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif //TNT_UTILS_QUADTREE_H
|
||||
88
thermion_dart/native/include/filament/utils/Range.h
Normal file
88
thermion_dart/native/include/filament/utils/Range.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_RANGE_H
|
||||
#define TNT_UTILS_RANGE_H
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
struct Range {
|
||||
using value_type = T;
|
||||
T first = 0;
|
||||
T last = 0; // this actually refers to one past the last
|
||||
|
||||
size_t size() const noexcept { return last - first; }
|
||||
bool empty() const noexcept { return !size(); }
|
||||
bool contains(const T& t) const noexcept { return first <= t && t < last; }
|
||||
|
||||
bool overlaps(const Range<T>& that) const noexcept {
|
||||
return (that.first < this->last) && (that.last > this->first);
|
||||
}
|
||||
|
||||
class const_iterator {
|
||||
friend struct Range;
|
||||
T value = {};
|
||||
|
||||
public:
|
||||
const_iterator() noexcept = default;
|
||||
explicit const_iterator(T value) noexcept : value(value) {}
|
||||
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
|
||||
const value_type operator*() const { return value; }
|
||||
const value_type operator[](size_t n) const { return value + n; }
|
||||
|
||||
const_iterator& operator++() { ++value; return *this; }
|
||||
const_iterator& operator--() { --value; return *this; }
|
||||
|
||||
const const_iterator operator++(int) { const_iterator t(value); value++; return t; }
|
||||
const const_iterator operator--(int) { const_iterator t(value); value--; return t; }
|
||||
|
||||
const_iterator operator+(size_t rhs) const { return { value + rhs }; }
|
||||
const_iterator operator+(size_t rhs) { return { value + rhs }; }
|
||||
const_iterator operator-(size_t rhs) const { return { value - rhs }; }
|
||||
|
||||
difference_type operator-(const_iterator const& rhs) const { return value - rhs.value; }
|
||||
|
||||
bool operator==(const_iterator const& rhs) const { return (value == rhs.value); }
|
||||
bool operator!=(const_iterator const& rhs) const { return (value != rhs.value); }
|
||||
bool operator>=(const_iterator const& rhs) const { return (value >= rhs.value); }
|
||||
bool operator> (const_iterator const& rhs) const { return (value > rhs.value); }
|
||||
bool operator<=(const_iterator const& rhs) const { return (value <= rhs.value); }
|
||||
bool operator< (const_iterator const& rhs) const { return (value < rhs.value); }
|
||||
};
|
||||
|
||||
const_iterator begin() noexcept { return const_iterator{ first }; }
|
||||
const_iterator end() noexcept { return const_iterator{ last }; }
|
||||
const_iterator begin() const noexcept { return const_iterator{ first }; }
|
||||
const_iterator end() const noexcept { return const_iterator{ last }; }
|
||||
|
||||
const_iterator front() const noexcept { return const_iterator{ first }; }
|
||||
const_iterator back() const noexcept { return const_iterator{ last - 1 }; }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_RANGE_H
|
||||
312
thermion_dart/native/include/filament/utils/RangeMap.h
Normal file
312
thermion_dart/native/include/filament/utils/RangeMap.h
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_RANGEMAP_H
|
||||
#define TNT_UTILS_RANGEMAP_H
|
||||
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Range.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* Sparse container for a series of ordered non-overlapping intervals.
|
||||
*
|
||||
* RangeMap has a low memory footprint if it contains fairly homogeneous data. Internally, the
|
||||
* intervals are automatically split and merged as elements are added or removed.
|
||||
*
|
||||
* Each interval maps to an instance of ValueType, which should support cheap equality checks
|
||||
* and copy assignment. (simple concrete types are ideal)
|
||||
*
|
||||
* KeyType should support operator< because intervals are internally sorted using std::map.
|
||||
*/
|
||||
template<typename KeyType, typename ValueType>
|
||||
class RangeMap {
|
||||
public:
|
||||
/**
|
||||
* Replaces all slots between first (inclusive) and last (exclusive).
|
||||
*/
|
||||
void add(KeyType first, KeyType last, const ValueType& value) noexcept {
|
||||
// First check if an existing range contains "first".
|
||||
Iterator iter = findRange(first);
|
||||
if (iter != end()) {
|
||||
const Range<KeyType> existing = getRange(iter);
|
||||
// Check if the existing range be extended.
|
||||
if (getValue(iter) == value) {
|
||||
if (existing.last < last) {
|
||||
wipe(existing.last, last);
|
||||
iter = shrink(iter, existing.first, last);
|
||||
mergeRight(iter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Split the existing range into two ranges.
|
||||
if (last < existing.last && first > existing.first) {
|
||||
iter = shrink(iter, existing.first, first);
|
||||
insert(first, last, value);
|
||||
insert(last, existing.last, getValue(iter));
|
||||
return;
|
||||
}
|
||||
clear(first, last);
|
||||
insert(first, last, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if an existing range contains the end of the new range.
|
||||
KeyType back = last;
|
||||
iter = findRange(--back);
|
||||
if (iter == end()) {
|
||||
wipe(first, last);
|
||||
insert(first, last, value);
|
||||
return;
|
||||
}
|
||||
const Range<KeyType> existing = getRange(iter);
|
||||
|
||||
// Check if the existing range be extended.
|
||||
if (getValue(iter) == value) {
|
||||
if (existing.first > first) {
|
||||
wipe(first, existing.first);
|
||||
iter = shrink(iter, first, existing.last);
|
||||
mergeLeft(iter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Clip the beginning of the existing range and potentially remove it.
|
||||
if (last < existing.last) {
|
||||
shrink(iter, last, existing.last);
|
||||
}
|
||||
wipe(first, last);
|
||||
insert(first, last, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand for the "add" method that inserts a single element.
|
||||
*/
|
||||
void set(KeyType key, const ValueType& value) noexcept {
|
||||
KeyType begin = key;
|
||||
add(begin, ++key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a range exists that encompasses the given key.
|
||||
*/
|
||||
bool has(KeyType key) const noexcept {
|
||||
return findRange(key) != mMap.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the element at the given location, panics if no element exists.
|
||||
*/
|
||||
const ValueType& get(KeyType key) const {
|
||||
ConstIterator iter = findRange(key);
|
||||
FILAMENT_CHECK_PRECONDITION(iter != end())
|
||||
<< "RangeMap: No element exists at the given key.";
|
||||
return getValue(iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements between begin (inclusive) and end (exclusive).
|
||||
*/
|
||||
void clear(KeyType first, KeyType last) noexcept {
|
||||
// Check if an existing range contains "first".
|
||||
Iterator iter = findRange(first);
|
||||
if (iter != end()) {
|
||||
const Range<KeyType> existing = getRange(iter);
|
||||
// Split the existing range into two ranges.
|
||||
if (last < existing.last && first > existing.first) {
|
||||
iter = shrink(iter, existing.first, first);
|
||||
insert(last, existing.last, getValue(iter));
|
||||
return;
|
||||
}
|
||||
// Clip one of the ends of the existing range or remove it.
|
||||
if (first > existing.first) {
|
||||
shrink(iter, existing.first, first);
|
||||
} else if (last < existing.last) {
|
||||
shrink(iter, last, existing.last);
|
||||
} else {
|
||||
wipe(first, last);
|
||||
}
|
||||
// There might be another range that intersects the cleared range, so try again.
|
||||
clear(first, last);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if an existing range contains the end of the new range.
|
||||
KeyType back = last;
|
||||
iter = findRange(--back);
|
||||
if (iter == end()) {
|
||||
wipe(first, last);
|
||||
return;
|
||||
}
|
||||
const Range<KeyType> existing = getRange(iter);
|
||||
|
||||
// Clip the beginning of the existing range and potentially remove it.
|
||||
if (last < existing.last) {
|
||||
shrink(iter, last, existing.last);
|
||||
}
|
||||
wipe(first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand for the "clear" method that clears a single element.
|
||||
*/
|
||||
void reset(KeyType key) noexcept {
|
||||
KeyType begin = key;
|
||||
clear(begin, ++key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of internal interval objects (rarely used).
|
||||
*/
|
||||
size_t rangeCount() const noexcept { return mMap.size(); }
|
||||
|
||||
private:
|
||||
|
||||
using Map = std::map<KeyType, std::pair<Range<KeyType>, ValueType>>;
|
||||
using Iterator = typename Map::iterator;
|
||||
using ConstIterator = typename Map::const_iterator;
|
||||
|
||||
ConstIterator begin() const noexcept { return mMap.begin(); }
|
||||
ConstIterator end() const noexcept { return mMap.end(); }
|
||||
|
||||
Iterator begin() noexcept { return mMap.begin(); }
|
||||
Iterator end() noexcept { return mMap.end(); }
|
||||
|
||||
Range<KeyType>& getRange(Iterator iter) const { return iter->second.first; }
|
||||
ValueType& getValue(Iterator iter) const { return iter->second.second; }
|
||||
|
||||
const Range<KeyType>& getRange(ConstIterator iter) const { return iter->second.first; }
|
||||
const ValueType& getValue(ConstIterator iter) const { return iter->second.second; }
|
||||
|
||||
// Private helper that assumes there is no existing range that overlaps the given range.
|
||||
void insert(KeyType first, KeyType last, const ValueType& value) noexcept {
|
||||
assert_invariant(!has(first));
|
||||
assert_invariant(!has(last - 1));
|
||||
|
||||
// Check if there is an adjacent range to the left than can be extended.
|
||||
KeyType previous = first;
|
||||
if (Iterator iter = findRange(--previous); iter != end() && getValue(iter) == value) {
|
||||
getRange(iter).last = last;
|
||||
mergeRight(iter);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there is an adjacent range to the right than can be extended.
|
||||
if (Iterator iter = findRange(last); iter != end() && getValue(iter) == value) {
|
||||
getRange(iter).first = first;
|
||||
return;
|
||||
}
|
||||
|
||||
mMap[first] = {Range<KeyType> { first, last }, value};
|
||||
}
|
||||
|
||||
// Private helper that erases all intervals that are wholly contained within the given range.
|
||||
// Note that this is quite different from the public "clear" method.
|
||||
void wipe(KeyType first, KeyType last) noexcept {
|
||||
// Find the first range whose beginning is greater than or equal to "first".
|
||||
Iterator iter = mMap.lower_bound(first);
|
||||
while (iter != end() && getRange(iter).first < last) {
|
||||
KeyType existing_last = getRange(iter).last;
|
||||
if (existing_last > last) {
|
||||
break;
|
||||
}
|
||||
iter = mMap.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if there is range to the right that touches the given range.
|
||||
// If so, erases it, extends the given range rightwards, and returns true.
|
||||
bool mergeRight(Iterator iter) {
|
||||
Iterator next = iter;
|
||||
if (++next == end() || getValue(next) != getValue(iter)) {
|
||||
return false;
|
||||
}
|
||||
if (getRange(next).first != getRange(iter).last) {
|
||||
return false;
|
||||
}
|
||||
getRange(iter).last = getRange(next).last;
|
||||
mMap.erase(next);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if there is range to the left that touches the given range.
|
||||
// If so, erases it, extends the given range leftwards, and returns true.
|
||||
bool mergeLeft(Iterator iter) {
|
||||
Iterator prev = iter;
|
||||
if (--prev == end() || getValue(prev) != getValue(iter)) {
|
||||
return false;
|
||||
}
|
||||
if (getRange(prev).last != getRange(iter).first) {
|
||||
return false;
|
||||
}
|
||||
getRange(iter).first = getRange(prev).first;
|
||||
mMap.erase(prev);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Private helper that clips one end of an existing range.
|
||||
Iterator shrink(Iterator iter, KeyType first, KeyType last) {
|
||||
assert_invariant(first < last);
|
||||
assert_invariant(getRange(iter).first == first || getRange(iter).last == last);
|
||||
std::pair<Range<KeyType>, ValueType> value = {{first, last}, iter->second.second};
|
||||
mMap.erase(iter);
|
||||
return mMap.insert({first, value}).first;
|
||||
}
|
||||
|
||||
// If the given key is encompassed by an existing range, returns an iterator for that range.
|
||||
// If no encompassing range exists, returns end().
|
||||
ConstIterator findRange(KeyType key) const noexcept {
|
||||
return findRangeT<ConstIterator>(*this, key);
|
||||
}
|
||||
|
||||
// If the given key is encompassed by an existing range, returns an iterator for that range.
|
||||
// If no encompassing range exists, returns end().
|
||||
Iterator findRange(KeyType key) noexcept {
|
||||
return findRangeT<Iterator>(*this, key);
|
||||
}
|
||||
|
||||
// This template method allows us to avoid code duplication for const and non-const variants of
|
||||
// findRange. C++17 has "std::as_const()" but that would not be helpful here, as we would still
|
||||
// need to convert a const iterator to a non-const iterator.
|
||||
template<typename IteratorType, typename SelfType>
|
||||
static IteratorType findRangeT(SelfType& instance, KeyType key) noexcept {
|
||||
// Find the first range whose beginning is greater than or equal to the given key.
|
||||
IteratorType iter = instance.mMap.lower_bound(key);
|
||||
if (iter != instance.end() && instance.getRange(iter).contains(key)) {
|
||||
return iter;
|
||||
}
|
||||
// If that was the first range, or if the map is empty, return false.
|
||||
if (iter == instance.begin()) {
|
||||
return instance.end();
|
||||
}
|
||||
// Check the range immediately previous to the one that was found.
|
||||
return instance.getRange(--iter).contains(key) ? iter : instance.end();
|
||||
}
|
||||
|
||||
// This maps from the start value of each range to the range itself.
|
||||
Map mMap;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_RANGEMAP_H
|
||||
105
thermion_dart/native/include/filament/utils/Stopwatch.h
Normal file
105
thermion_dart/native/include/filament/utils/Stopwatch.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_STOPWATCH_H
|
||||
#define TNT_UTILS_STOPWATCH_H
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <ratio>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A very basic Stopwatch class
|
||||
*/
|
||||
|
||||
template<typename Clock = std::chrono::steady_clock>
|
||||
class Stopwatch {
|
||||
public:
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
private:
|
||||
time_point mStart;
|
||||
duration mMinLap = std::numeric_limits<duration>::max();
|
||||
duration mMaxLap{};
|
||||
std::chrono::duration<double, std::nano> mAvgLap{};
|
||||
size_t mCount = 0;
|
||||
const char* mName = nullptr;
|
||||
|
||||
public:
|
||||
// Create a Stopwatch with a name and clock
|
||||
explicit Stopwatch(const char* name) noexcept: mName(name) {}
|
||||
|
||||
// Logs min/avg/max lap time
|
||||
~Stopwatch() noexcept;
|
||||
|
||||
// start the stopwatch
|
||||
inline void start() noexcept {
|
||||
mStart = Clock::now();
|
||||
}
|
||||
|
||||
// stop the stopwatch
|
||||
inline void stop() noexcept {
|
||||
auto d = Clock::now() - mStart;
|
||||
mMinLap = std::min(mMinLap, d);
|
||||
mMaxLap = std::max(mMaxLap, d);
|
||||
mAvgLap = (mAvgLap * mCount + d) / (mCount + 1);
|
||||
mCount++;
|
||||
}
|
||||
|
||||
// get the minimum lap time recorded
|
||||
duration getMinLapTime() const noexcept { return mMinLap; }
|
||||
|
||||
// get the maximum lap time recorded
|
||||
duration getMaxLapTime() const noexcept { return mMaxLap; }
|
||||
|
||||
// get the average lap time
|
||||
duration getAverageLapTime() const noexcept { return mAvgLap; }
|
||||
};
|
||||
|
||||
template<typename Clock>
|
||||
Stopwatch<Clock>::~Stopwatch() noexcept {
|
||||
slog.d << "Stopwatch \"" << mName << "\" : ["
|
||||
<< mMinLap.count() << ", "
|
||||
<< std::chrono::duration_cast<duration>(mAvgLap).count() << ", "
|
||||
<< mMaxLap.count() << "] ns" << io::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* AutoStopwatch can be used to start and stop a Stopwatch automatically
|
||||
* when entering and exiting a scope.
|
||||
*/
|
||||
template<typename Stopwatch>
|
||||
class AutoStopwatch {
|
||||
Stopwatch& stopwatch;
|
||||
public:
|
||||
inline explicit AutoStopwatch(Stopwatch& stopwatch) noexcept: stopwatch(stopwatch) {
|
||||
stopwatch.start();
|
||||
}
|
||||
|
||||
inline ~AutoStopwatch() noexcept { stopwatch.stop(); }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_STOPWATCH_H
|
||||
26
thermion_dart/native/include/filament/utils/ThermalManager.h
Normal file
26
thermion_dart/native/include/filament/utils/ThermalManager.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMALMANAGER_H
|
||||
#define TNT_UTILS_THERMALMANAGER_H
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <utils/android/ThermalManager.h>
|
||||
#else
|
||||
#include <utils/generic/ThermalManager.h>
|
||||
#endif
|
||||
|
||||
#endif // TNT_UTILS_THERMALMANAGER_H
|
||||
32
thermion_dart/native/include/filament/utils/ThreadUtils.h
Normal file
32
thermion_dart/native/include/filament/utils/ThreadUtils.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THREADUTILS_H
|
||||
#define TNT_UTILS_THREADUTILS_H
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class ThreadUtils {
|
||||
public:
|
||||
static std::thread::id getThreadId() noexcept;
|
||||
static bool isThisThread(std::thread::id id) noexcept;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_THREADUTILS_H
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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_WORKSTEALINGDEQUEUE_H
|
||||
#define TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A templated, lockless, fixed-size work-stealing dequeue
|
||||
*
|
||||
*
|
||||
* top bottom
|
||||
* v v
|
||||
* |----|----|----|----|----|----|
|
||||
* steal() push(), pop()
|
||||
* any thread main thread
|
||||
*
|
||||
* References:
|
||||
* - This code is largely inspired from
|
||||
* https://blog.molecular-matters.com/2015/09/25/job-system-2-0-lock-free-work-stealing-part-3-going-lock-free/
|
||||
* - other implementations
|
||||
* https://github.com/ConorWilliams/ConcurrentDeque/blob/main/include/riften/deque.hpp
|
||||
* https://github.com/ssbl/concurrent-deque/blob/master/include/deque.hpp
|
||||
* https://github.com/taskflow/work-stealing-queue/blob/master/wsq.hpp
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
class WorkStealingDequeue {
|
||||
static_assert(!(COUNT & (COUNT - 1)), "COUNT must be a power of two");
|
||||
static constexpr size_t MASK = COUNT - 1;
|
||||
|
||||
// mTop and mBottom must be signed integers. We use 64-bits atomics so we don't have
|
||||
// to worry about wrapping around.
|
||||
using index_t = int64_t;
|
||||
|
||||
std::atomic<index_t> mTop = { 0 }; // written/read in pop()/steal()
|
||||
std::atomic<index_t> mBottom = { 0 }; // written only in pop(), read in push(), steal()
|
||||
|
||||
TYPE mItems[COUNT];
|
||||
|
||||
// NOTE: it's not safe to return a reference because getItemAt() can be called
|
||||
// concurrently and the caller could std::move() the item unsafely.
|
||||
TYPE getItemAt(index_t index) noexcept { return mItems[index & MASK]; }
|
||||
|
||||
void setItemAt(index_t index, TYPE item) noexcept { mItems[index & MASK] = item; }
|
||||
|
||||
public:
|
||||
using value_type = TYPE;
|
||||
|
||||
inline void push(TYPE item) noexcept;
|
||||
inline TYPE pop() noexcept;
|
||||
inline TYPE steal() noexcept;
|
||||
|
||||
size_t getSize() const noexcept { return COUNT; }
|
||||
|
||||
// for debugging only...
|
||||
size_t getCount() const noexcept {
|
||||
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||
index_t top = mTop.load(std::memory_order_relaxed);
|
||||
return bottom - top;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds an item at the BOTTOM of the queue.
|
||||
*
|
||||
* Must be called from the main thread.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
void WorkStealingDequeue<TYPE, COUNT>::push(TYPE item) noexcept {
|
||||
// std::memory_order_relaxed is sufficient because this load doesn't acquire anything from
|
||||
// another thread. mBottom is only written in pop() which cannot be concurrent with push()
|
||||
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||
setItemAt(bottom, item);
|
||||
|
||||
// Here we need std::memory_order_release because we release, the item we just pushed, to other
|
||||
// threads which are calling steal().
|
||||
// However, generally seq_cst cannot be mixed with other memory orders. So we must use seq_cst.
|
||||
// see: https://plv.mpi-sws.org/scfix/paper.pdf
|
||||
mBottom.store(bottom + 1, std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an item from the BOTTOM of the queue.
|
||||
*
|
||||
* Must be called from the main thread.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
TYPE WorkStealingDequeue<TYPE, COUNT>::pop() noexcept {
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||
// Note however that this is not a typical acquire/release operation:
|
||||
// - not acquire because mBottom is only written in push() which is not concurrent
|
||||
// - not release because we're not publishing anything to steal() here
|
||||
//
|
||||
// QUESTION: does this prevent mTop load below to be reordered before the "store" part of
|
||||
// fetch_sub()? Hopefully it does. If not we'd need a full memory barrier.
|
||||
//
|
||||
index_t bottom = mBottom.fetch_sub(1, std::memory_order_seq_cst) - 1;
|
||||
|
||||
// bottom could be -1 if we tried to pop() from an empty queue. This will be corrected below.
|
||||
assert( bottom >= -1 );
|
||||
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||
// Note however that this is not a typical acquire operation
|
||||
// (i.e. other thread's writes of mTop don't publish data)
|
||||
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||
|
||||
if (top < bottom) {
|
||||
// Queue isn't empty, and it's not the last item, just return it, this is the common case.
|
||||
return getItemAt(bottom);
|
||||
}
|
||||
|
||||
TYPE item{};
|
||||
if (top == bottom) {
|
||||
// we just took the last item
|
||||
item = getItemAt(bottom);
|
||||
|
||||
// Because we know we took the last item, we could be racing with steal() -- the last
|
||||
// item being both at the top and bottom of the queue.
|
||||
// We resolve this potential race by also stealing that item from ourselves.
|
||||
if (mTop.compare_exchange_strong(top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed)) {
|
||||
// Success: we stole our last item from ourselves, meaning that a concurrent steal()
|
||||
// would have failed.
|
||||
// mTop now equals top + 1, we adjust top to make the queue empty.
|
||||
top++;
|
||||
} else {
|
||||
// Failure: mTop was not equal to top, which means the item was stolen under our feet.
|
||||
// `top` now equals to mTop. Simply discard the item we just popped.
|
||||
// The queue is now empty.
|
||||
item = TYPE();
|
||||
}
|
||||
} else {
|
||||
// We could be here if the item was stolen just before we read mTop, we'll adjust
|
||||
// mBottom below.
|
||||
assert(top - bottom == 1);
|
||||
}
|
||||
|
||||
// Here, we only need std::memory_order_relaxed because we're not publishing any data.
|
||||
// No concurrent writes to mBottom possible, it's always safe to write mBottom.
|
||||
// However, generally seq_cst cannot be mixed with other memory orders. So we must use seq_cst.
|
||||
// see: https://plv.mpi-sws.org/scfix/paper.pdf
|
||||
mBottom.store(top, std::memory_order_seq_cst);
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Steals an item from the TOP of another thread's queue.
|
||||
*
|
||||
* This can be called concurrently with steal(), push() or pop()
|
||||
*
|
||||
* steal() never fails, either there is an item and it atomically takes it, or there isn't and
|
||||
* it returns an empty item.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
TYPE WorkStealingDequeue<TYPE, COUNT>::steal() noexcept {
|
||||
while (true) {
|
||||
/*
|
||||
* Note: A Key component of this algorithm is that mTop is read before mBottom here
|
||||
* (and observed as such in other threads)
|
||||
*/
|
||||
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||
// Note however that this is not a typical acquire operation
|
||||
// (i.e. other thread's writes of mTop don't publish data)
|
||||
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||
|
||||
// std::memory_order_acquire is needed because we're acquiring items published in push().
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||
index_t bottom = mBottom.load(std::memory_order_seq_cst);
|
||||
|
||||
if (top >= bottom) {
|
||||
// queue is empty
|
||||
return TYPE();
|
||||
}
|
||||
|
||||
// The queue isn't empty
|
||||
TYPE item(getItemAt(top));
|
||||
if (mTop.compare_exchange_strong(top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed)) {
|
||||
// success: we stole an item, just return it.
|
||||
return item;
|
||||
}
|
||||
// failure: the item we just tried to steal was pop()'ed under our feet,
|
||||
// simply discard it; nothing to do -- it's okay to try again.
|
||||
// However, item might be corrupted, so it must be trivially destructible
|
||||
static_assert(std::is_trivially_destructible_v<TYPE>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||
123
thermion_dart/native/include/filament/utils/Zip2Iterator.h
Normal file
123
thermion_dart/native/include/filament/utils/Zip2Iterator.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_ZIP2ITERATOR_H
|
||||
#define TNT_UTILS_ZIP2ITERATOR_H
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A random access iterator that wraps two other random access iterators.
|
||||
* This mostly exists so that one can sort an array using values from another.
|
||||
*/
|
||||
|
||||
template<typename It1, typename It2>
|
||||
class Zip2Iterator {
|
||||
std::pair<It1, It2> mIt;
|
||||
using Ref1 = typename std::iterator_traits<It1>::reference;
|
||||
using Ref2 = typename std::iterator_traits<It2>::reference;
|
||||
using Val1 = typename std::iterator_traits<It1>::value_type;
|
||||
using Val2 = typename std::iterator_traits<It2>::value_type;
|
||||
|
||||
public:
|
||||
struct Ref : public std::pair<Ref1, Ref2> {
|
||||
using std::pair<Ref1, Ref2>::pair;
|
||||
using std::pair<Ref1, Ref2>::operator=;
|
||||
private:
|
||||
friend void swap(Ref lhs, Ref rhs) {
|
||||
using std::swap;
|
||||
swap(lhs.first, rhs.first);
|
||||
swap(lhs.second, rhs.second);
|
||||
}
|
||||
};
|
||||
|
||||
using value_type = std::pair<Val1, Val2>;
|
||||
using reference = Ref;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
Zip2Iterator() = default;
|
||||
Zip2Iterator(It1 first, It2 second) : mIt({first, second}) {}
|
||||
Zip2Iterator(Zip2Iterator const& rhs) noexcept = default;
|
||||
Zip2Iterator& operator=(Zip2Iterator const& rhs) = default;
|
||||
|
||||
reference operator*() const { return { *mIt.first, *mIt.second }; }
|
||||
|
||||
reference operator[](size_t n) const { return *(*this + n); }
|
||||
|
||||
Zip2Iterator& operator++() {
|
||||
++mIt.first;
|
||||
++mIt.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator--() {
|
||||
--mIt.first;
|
||||
--mIt.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix operator needed by Microsoft C++
|
||||
const Zip2Iterator operator++(int) {
|
||||
Zip2Iterator t(*this);
|
||||
mIt.first++;
|
||||
mIt.second++;
|
||||
return t;
|
||||
}
|
||||
|
||||
const Zip2Iterator operator--(int) {
|
||||
Zip2Iterator t(*this);
|
||||
mIt.first--;
|
||||
mIt.second--;
|
||||
return t;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator+=(size_t v) {
|
||||
mIt.first += v;
|
||||
mIt.second += v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator-=(size_t v) {
|
||||
mIt.first -= v;
|
||||
mIt.second -= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator operator+(size_t rhs) const { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||
Zip2Iterator operator+(size_t rhs) { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||
Zip2Iterator operator-(size_t rhs) const { return { mIt.first - rhs, mIt.second - rhs }; }
|
||||
|
||||
difference_type operator-(Zip2Iterator const& rhs) const { return mIt.first - rhs.mIt.first; }
|
||||
|
||||
bool operator==(Zip2Iterator const& rhs) const { return (mIt.first == rhs.mIt.first); }
|
||||
bool operator!=(Zip2Iterator const& rhs) const { return (mIt.first != rhs.mIt.first); }
|
||||
bool operator>=(Zip2Iterator const& rhs) const { return (mIt.first >= rhs.mIt.first); }
|
||||
bool operator> (Zip2Iterator const& rhs) const { return (mIt.first > rhs.mIt.first); }
|
||||
bool operator<=(Zip2Iterator const& rhs) const { return (mIt.first <= rhs.mIt.first); }
|
||||
bool operator< (Zip2Iterator const& rhs) const { return (mIt.first < rhs.mIt.first); }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ZIP2ITERATOR_H
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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_PERFORMANCEHINTMANAGER_H
|
||||
#define TNT_UTILS_ANDROID_PERFORMANCEHINTMANAGER_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
namespace details {
|
||||
struct PerformanceHintManager;
|
||||
} // namespace details
|
||||
|
||||
class UTILS_PUBLIC PerformanceHintManager :
|
||||
private PrivateImplementation<details::PerformanceHintManager> {
|
||||
friend struct details::PerformanceHintManager;
|
||||
struct SessionDetails;
|
||||
|
||||
public:
|
||||
class UTILS_PUBLIC Session : PrivateImplementation<SessionDetails> {
|
||||
friend class PerformanceHintManager;
|
||||
friend struct SessionDetails;
|
||||
public:
|
||||
Session() noexcept;
|
||||
Session(PerformanceHintManager& manager,
|
||||
int32_t const* threadIds, size_t size,
|
||||
int64_t initialTargetWorkDurationNanos) noexcept;
|
||||
~Session() noexcept;
|
||||
|
||||
Session(Session&& rhs) noexcept;
|
||||
Session& operator=(Session&& rhs) noexcept;
|
||||
Session(Session const& rhs) = delete;
|
||||
Session& operator=(Session const& rhs) = delete;
|
||||
|
||||
bool isValid() const;
|
||||
int updateTargetWorkDuration(int64_t targetDurationNanos) noexcept;
|
||||
int reportActualWorkDuration(int64_t actualDurationNanos) noexcept;
|
||||
};
|
||||
|
||||
// caveat: This must be called on a Java thread
|
||||
PerformanceHintManager() noexcept;
|
||||
~PerformanceHintManager() noexcept;
|
||||
|
||||
// Whether PerformanceHintManager APIs are supported (which doesn't mean PerformanceHintManager
|
||||
// itself is, use isValid()).
|
||||
static bool isSupported() noexcept;
|
||||
|
||||
// Whether PerformanceHintManager can be used.
|
||||
bool isValid() const;
|
||||
|
||||
int64_t getPreferredUpdateRateNanos() const noexcept;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif //TNT_UTILS_ANDROID_PERFORMANCEHINTMANAGER_H
|
||||
242
thermion_dart/native/include/filament/utils/android/Systrace.h
Normal file
242
thermion_dart/native/include/filament/utils/android/Systrace.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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 ___trctx(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) \
|
||||
___trctx.traceBegin(SYSTRACE_TAG, name)
|
||||
|
||||
#define SYSTRACE_NAME_END() \
|
||||
___trctx.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) \
|
||||
___trctx.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) \
|
||||
___trctx.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) \
|
||||
___trctx.value(SYSTRACE_TAG, name, int32_t(val))
|
||||
|
||||
#define SYSTRACE_VALUE64(name, val) \
|
||||
___trctx.value(SYSTRACE_TAG, name, int64_t(val))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// No user serviceable code below...
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace utils {
|
||||
namespace details {
|
||||
|
||||
class UTILS_PUBLIC 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 UTILS_PUBLIC 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);
|
||||
}
|
||||
|
||||
private:
|
||||
Systrace mTrace;
|
||||
const uint32_t mTag;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ANDROID_SYSTRACE_H
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMALMANAGER_H
|
||||
#define TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct AThermalManager;
|
||||
|
||||
namespace utils {
|
||||
|
||||
class ThermalManager {
|
||||
public:
|
||||
enum class ThermalStatus : int8_t {
|
||||
ERROR = -1,
|
||||
NONE,
|
||||
LIGHT,
|
||||
MODERATE,
|
||||
SEVERE,
|
||||
CRITICAL,
|
||||
EMERGENCY,
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
ThermalManager();
|
||||
~ThermalManager();
|
||||
|
||||
// Movable
|
||||
ThermalManager(ThermalManager&& rhs) noexcept;
|
||||
ThermalManager& operator=(ThermalManager&& rhs) noexcept;
|
||||
|
||||
// not copiable
|
||||
ThermalManager(ThermalManager const& rhs) = delete;
|
||||
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||
|
||||
ThermalStatus getCurrentThermalStatus() const noexcept;
|
||||
|
||||
private:
|
||||
AThermalManager* mThermalManager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||
34
thermion_dart/native/include/filament/utils/api_level.h
Normal file
34
thermion_dart/native/include/filament/utils/api_level.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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_APILEVEL_H
|
||||
#define TNT_UTILS_APILEVEL_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* Returns this platform's API level. On Android this function will return
|
||||
* the API level as defined by the SDK API level version. If a platform does
|
||||
* not have an API level, this function returns 0.
|
||||
*/
|
||||
UTILS_PUBLIC
|
||||
int api_level();
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_APILEVEL_H
|
||||
33
thermion_dart/native/include/filament/utils/architecture.h
Normal file
33
thermion_dart/native/include/filament/utils/architecture.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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_ARCHITECTURE_H
|
||||
#define TNT_UTILS_ARCHITECTURE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
constexpr size_t CACHELINE_SIZE = 64;
|
||||
|
||||
namespace arch {
|
||||
|
||||
size_t getPageSize() noexcept;
|
||||
|
||||
} // namespace arch
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ARCHITECTURE_H
|
||||
28
thermion_dart/native/include/filament/utils/ashmem.h
Normal file
28
thermion_dart/native/include/filament/utils/ashmem.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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_ASHMEM_H
|
||||
#define TNT_UTILS_ASHMEM_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
int ashmem_create_region(const char *name, size_t size);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ASHMEM_H
|
||||
243
thermion_dart/native/include/filament/utils/darwin/Systrace.h
Normal file
243
thermion_dart/native/include/filament/utils/darwin/Systrace.h
Normal 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
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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_GENERIC_CONDITION_H
|
||||
#define TNT_UTILS_GENERIC_CONDITION_H
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class Condition : public std::condition_variable {
|
||||
public:
|
||||
using std::condition_variable::condition_variable;
|
||||
|
||||
inline void notify_n(size_t n) noexcept {
|
||||
if (n == 1) {
|
||||
notify_one();
|
||||
} else if (n > 1) {
|
||||
notify_all();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_GENERIC_CONDITION_H
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_GENERIC_THERMALMANAGER_H
|
||||
#define TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class ThermalManager {
|
||||
public:
|
||||
enum class ThermalStatus : int8_t {
|
||||
ERROR = -1,
|
||||
NONE,
|
||||
LIGHT,
|
||||
MODERATE,
|
||||
SEVERE,
|
||||
CRITICAL,
|
||||
EMERGENCY,
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
ThermalManager() = default;
|
||||
|
||||
// Movable
|
||||
ThermalManager(ThermalManager&& rhs) noexcept = default;
|
||||
ThermalManager& operator=(ThermalManager&& rhs) noexcept = default;
|
||||
|
||||
// not copiable
|
||||
ThermalManager(ThermalManager const& rhs) = delete;
|
||||
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||
|
||||
ThermalStatus getCurrentThermalStatus() const noexcept {
|
||||
return ThermalStatus::NONE;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||
123
thermion_dart/native/include/filament/utils/linux/Condition.h
Normal file
123
thermion_dart/native/include/filament/utils/linux/Condition.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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
|
||||
26
thermion_dart/native/include/filament/utils/string.h
Normal file
26
thermion_dart/native/include/filament/utils/string.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_STRING_H
|
||||
#define TNT_UTILS_STRING_H
|
||||
|
||||
namespace utils {
|
||||
|
||||
float strtof_c(const char* start, char** end);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_STRING_H
|
||||
40
thermion_dart/native/include/filament/utils/trap.h
Normal file
40
thermion_dart/native/include/filament/utils/trap.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_TRAP_H
|
||||
#define TNT_UTILS_TRAP_H
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <Windows.h>
|
||||
#include <utils/unwindows.h>
|
||||
#endif
|
||||
|
||||
namespace utils {
|
||||
|
||||
// This can be used as a programmatic breakpoint.
|
||||
inline void debug_trap() noexcept {
|
||||
#if defined(WIN32)
|
||||
DebugBreak();
|
||||
#else
|
||||
std::raise(SIGINT);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_TRAP_H
|
||||
61
thermion_dart/native/include/filament/utils/vector.h
Normal file
61
thermion_dart/native/include/filament/utils/vector.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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_VECTOR_H
|
||||
#define TNT_UTILS_VECTOR_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* Inserts the specified item in the vector at its sorted position.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void insert_sorted(std::vector<T>& v, T item) {
|
||||
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||
v.insert(pos, std::move(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified item in the vector at its sorted position.
|
||||
* The item type must implement the < operator. If the specified
|
||||
* item is already present in the vector, this method returns without
|
||||
* inserting the item again.
|
||||
*
|
||||
* @return True if the item was inserted at is sorted position, false
|
||||
* if the item already exists in the vector.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool insert_sorted_unique(std::vector<T>& v, T item) {
|
||||
if (UTILS_LIKELY(v.size() == 0 || v.back() < item)) {
|
||||
v.push_back(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||
if (UTILS_LIKELY(pos == v.end() || item < *pos)) {
|
||||
v.insert(pos, std::move(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end utils namespace
|
||||
|
||||
#endif // TNT_UTILS_VECTOR_H
|
||||
33
thermion_dart/native/include/filament/utils/win32/stdtypes.h
Normal file
33
thermion_dart/native/include/filament/utils/win32/stdtypes.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_WIN32_STDTYPES_H
|
||||
#define TNT_UTILS_WIN32_STDTYPES_H
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
// Copied from linux libc sys/stat.h:
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define PATH_MAX (MAX_PATH)
|
||||
|
||||
// For getcwd
|
||||
#include <direct.h>
|
||||
#define getcwd _getcwd
|
||||
|
||||
#endif
|
||||
#endif // TNT_UTILS_WIN32_STDTYPES_H
|
||||
Reference in New Issue
Block a user