Modernize atomics
- Based on C++11's `atomic` - Reworked `SafeRefCount` (based on the rewrite by @hpvb) - Replaced free atomic functions by the new `SafeNumeric<T>` - Replaced wrong cases of `volatile bool` by the new `SafeFlag` - Platform-specific implementations no longer needed Co-authored-by: Hein-Pieter van Braam-Stewart <hp@tmm.cx>
This commit is contained in:
parent
8870f43d74
commit
8e128726f0
58 changed files with 650 additions and 639 deletions
|
@ -1990,7 +1990,7 @@ void _Thread::_start_func(void *ud) {
|
|||
}
|
||||
|
||||
Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
|
||||
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started.");
|
||||
ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started.");
|
||||
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
|
||||
|
@ -1999,7 +1999,7 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
|
|||
target_method = p_method;
|
||||
target_instance = p_instance;
|
||||
userdata = p_userdata;
|
||||
active = true;
|
||||
active.set();
|
||||
|
||||
Ref<_Thread> *ud = memnew(Ref<_Thread>(this));
|
||||
|
||||
|
@ -2015,14 +2015,14 @@ String _Thread::get_id() const {
|
|||
}
|
||||
|
||||
bool _Thread::is_active() const {
|
||||
return active;
|
||||
return active.is_set();
|
||||
}
|
||||
|
||||
Variant _Thread::wait_to_finish() {
|
||||
ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion.");
|
||||
ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion.");
|
||||
thread.wait_to_finish();
|
||||
Variant r = ret;
|
||||
active = false;
|
||||
active.clear();
|
||||
target_method = StringName();
|
||||
target_instance = nullptr;
|
||||
userdata = Variant();
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "core/os/os.h"
|
||||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
class _ResourceLoader : public Object {
|
||||
GDCLASS(_ResourceLoader, Object);
|
||||
|
@ -559,7 +560,7 @@ class _Thread : public Reference {
|
|||
protected:
|
||||
Variant ret;
|
||||
Variant userdata;
|
||||
volatile bool active = false;
|
||||
SafeFlag active;
|
||||
Object *target_instance = nullptr;
|
||||
StringName target_method;
|
||||
Thread thread;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
class String;
|
||||
|
||||
enum ErrorHandlerType {
|
||||
|
@ -577,10 +579,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
|
|||
*/
|
||||
#define WARN_DEPRECATED \
|
||||
if (true) { \
|
||||
static volatile bool warning_shown = false; \
|
||||
if (!warning_shown) { \
|
||||
static SafeFlag warning_shown; \
|
||||
if (!warning_shown.is_set()) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \
|
||||
warning_shown = true; \
|
||||
warning_shown.set(); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
@ -590,10 +592,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
|
|||
*/
|
||||
#define WARN_DEPRECATED_MSG(m_msg) \
|
||||
if (true) { \
|
||||
static volatile bool warning_shown = false; \
|
||||
if (!warning_shown) { \
|
||||
static SafeFlag warning_shown; \
|
||||
if (!warning_shown.is_set()) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \
|
||||
warning_shown = true; \
|
||||
warning_shown.set(); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
|
|
@ -40,13 +40,13 @@ VARIANT_ENUM_CAST(IP::ResolverStatus);
|
|||
|
||||
struct _IP_ResolverPrivate {
|
||||
struct QueueItem {
|
||||
volatile IP::ResolverStatus status;
|
||||
SafeNumeric<IP::ResolverStatus> status;
|
||||
IP_Address response;
|
||||
String hostname;
|
||||
IP::Type type;
|
||||
|
||||
void clear() {
|
||||
status = IP::RESOLVER_STATUS_NONE;
|
||||
status.set(IP::RESOLVER_STATUS_NONE);
|
||||
response = IP_Address();
|
||||
type = IP::TYPE_NONE;
|
||||
hostname = "";
|
||||
|
@ -61,7 +61,7 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
IP::ResolverID find_empty_id() const {
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
if (queue[i].status == IP::RESOLVER_STATUS_NONE) {
|
||||
if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -77,15 +77,15 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
void resolve_queues() {
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
if (queue[i].status != IP::RESOLVER_STATUS_WAITING) {
|
||||
if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) {
|
||||
continue;
|
||||
}
|
||||
queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
|
||||
|
||||
if (!queue[i].response.is_valid()) {
|
||||
queue[i].status = IP::RESOLVER_STATUS_ERROR;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
|
||||
} else {
|
||||
queue[i].status = IP::RESOLVER_STATUS_DONE;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,10 +137,10 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
|
|||
resolver->queue[id].type = p_type;
|
||||
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
|
||||
resolver->queue[id].response = resolver->cache[key];
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
} else {
|
||||
resolver->queue[id].response = IP_Address();
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
|
||||
if (resolver->thread.is_started()) {
|
||||
resolver->sem.post();
|
||||
} else {
|
||||
|
@ -156,12 +156,12 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
|
|||
|
||||
MutexLock lock(resolver->mutex);
|
||||
|
||||
if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
|
||||
if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
|
||||
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
|
||||
resolver->mutex.unlock();
|
||||
return IP::RESOLVER_STATUS_NONE;
|
||||
}
|
||||
return resolver->queue[p_id].status;
|
||||
return resolver->queue[p_id].status.get();
|
||||
}
|
||||
|
||||
IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
|
||||
|
@ -169,7 +169,7 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
|
|||
|
||||
MutexLock lock(resolver->mutex);
|
||||
|
||||
if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
|
||||
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
|
||||
ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
|
||||
resolver->mutex.unlock();
|
||||
return IP_Address();
|
||||
|
@ -183,7 +183,7 @@ void IP::erase_resolve_item(ResolverID p_id) {
|
|||
|
||||
MutexLock lock(resolver->mutex);
|
||||
|
||||
resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
|
||||
resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
|
||||
}
|
||||
|
||||
void IP::clear_cache(const String &p_hostname) {
|
||||
|
|
|
@ -1727,7 +1727,7 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
|
|||
if (!_script_instance_bindings[p_script_language_index]) {
|
||||
void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
|
||||
if (script_data) {
|
||||
atomic_increment(&instance_binding_count);
|
||||
instance_binding_count.increment();
|
||||
_script_instance_bindings[p_script_language_index] = script_data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/map.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/templates/set.h"
|
||||
#include "core/templates/vmap.h"
|
||||
#include "core/variant/callable_bind.h"
|
||||
|
@ -485,7 +486,7 @@ private:
|
|||
|
||||
friend class Reference;
|
||||
bool type_is_reference = false;
|
||||
uint32_t instance_binding_count = 0;
|
||||
SafeNumeric<uint32_t> instance_binding_count;
|
||||
void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
|
||||
|
||||
Object(bool p_reference);
|
||||
|
|
|
@ -62,7 +62,7 @@ bool Reference::reference() {
|
|||
if (get_script_instance()) {
|
||||
get_script_instance()->refcount_incremented();
|
||||
}
|
||||
if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
|
||||
if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
|
||||
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
|
||||
if (_script_instance_bindings[i]) {
|
||||
ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
|
||||
|
@ -83,7 +83,7 @@ bool Reference::unreference() {
|
|||
bool script_ret = get_script_instance()->refcount_decremented();
|
||||
die = die && script_ret;
|
||||
}
|
||||
if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
|
||||
if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
|
||||
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
|
||||
if (_script_instance_bindings[i]) {
|
||||
bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
|
||||
|
|
|
@ -60,11 +60,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t Memory::mem_usage = 0;
|
||||
uint64_t Memory::max_usage = 0;
|
||||
SafeNumeric<uint64_t> Memory::mem_usage;
|
||||
SafeNumeric<uint64_t> Memory::max_usage;
|
||||
#endif
|
||||
|
||||
uint64_t Memory::alloc_count = 0;
|
||||
SafeNumeric<uint64_t> Memory::alloc_count;
|
||||
|
||||
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
@ -77,7 +77,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
|||
|
||||
ERR_FAIL_COND_V(!mem, nullptr);
|
||||
|
||||
atomic_increment(&alloc_count);
|
||||
alloc_count.increment();
|
||||
|
||||
if (prepad) {
|
||||
uint64_t *s = (uint64_t *)mem;
|
||||
|
@ -86,8 +86,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
|||
uint8_t *s8 = (uint8_t *)mem;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
atomic_add(&mem_usage, p_bytes);
|
||||
atomic_exchange_if_greater(&max_usage, mem_usage);
|
||||
uint64_t new_mem_usage = mem_usage.add(p_bytes);
|
||||
max_usage.exchange_if_greater(new_mem_usage);
|
||||
#endif
|
||||
return s8 + PAD_ALIGN;
|
||||
} else {
|
||||
|
@ -114,10 +114,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (p_bytes > *s) {
|
||||
atomic_add(&mem_usage, p_bytes - *s);
|
||||
atomic_exchange_if_greater(&max_usage, mem_usage);
|
||||
uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
|
||||
max_usage.exchange_if_greater(new_mem_usage);
|
||||
} else {
|
||||
atomic_sub(&mem_usage, *s - p_bytes);
|
||||
mem_usage.sub(*s - p_bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -156,14 +156,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
|
|||
bool prepad = p_pad_align;
|
||||
#endif
|
||||
|
||||
atomic_decrement(&alloc_count);
|
||||
alloc_count.decrement();
|
||||
|
||||
if (prepad) {
|
||||
mem -= PAD_ALIGN;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t *s = (uint64_t *)mem;
|
||||
atomic_sub(&mem_usage, *s);
|
||||
mem_usage.sub(*s);
|
||||
#endif
|
||||
|
||||
free(mem);
|
||||
|
@ -178,7 +178,7 @@ uint64_t Memory::get_mem_available() {
|
|||
|
||||
uint64_t Memory::get_mem_usage() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
return mem_usage;
|
||||
return mem_usage.get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -186,7 +186,7 @@ uint64_t Memory::get_mem_usage() {
|
|||
|
||||
uint64_t Memory::get_mem_max_usage() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
return max_usage;
|
||||
return max_usage.get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
|
|
@ -43,11 +43,11 @@
|
|||
class Memory {
|
||||
Memory();
|
||||
#ifdef DEBUG_ENABLED
|
||||
static uint64_t mem_usage;
|
||||
static uint64_t max_usage;
|
||||
static SafeNumeric<uint64_t> mem_usage;
|
||||
static SafeNumeric<uint64_t> max_usage;
|
||||
#endif
|
||||
|
||||
static uint64_t alloc_count;
|
||||
static SafeNumeric<uint64_t> alloc_count;
|
||||
|
||||
public:
|
||||
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
|
||||
|
|
|
@ -34,13 +34,15 @@
|
|||
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
Error (*Thread::set_name_func)(const String &) = nullptr;
|
||||
void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
|
||||
void (*Thread::init_func)() = nullptr;
|
||||
void (*Thread::term_func)() = nullptr;
|
||||
|
||||
Thread::ID Thread::main_thread_id = 1;
|
||||
Thread::ID Thread::last_thread_id = 1;
|
||||
SafeNumeric<Thread::ID> Thread::last_thread_id{ 1 };
|
||||
thread_local Thread::ID Thread::caller_id = 1;
|
||||
|
||||
void Thread::_set_platform_funcs(
|
||||
|
@ -79,7 +81,7 @@ void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_
|
|||
std::thread empty_thread;
|
||||
thread.swap(empty_thread);
|
||||
}
|
||||
id = atomic_increment(&last_thread_id);
|
||||
id = last_thread_id.increment();
|
||||
std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user);
|
||||
thread.swap(new_thread);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/typedefs.h"
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
|
@ -61,7 +62,7 @@ private:
|
|||
friend class Main;
|
||||
|
||||
static ID main_thread_id;
|
||||
static ID last_thread_id;
|
||||
static SafeNumeric<Thread::ID> last_thread_id;
|
||||
|
||||
ID id = 0;
|
||||
static thread_local ID caller_id;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
template <class C, class U>
|
||||
struct ThreadArrayProcessData {
|
||||
uint32_t elements;
|
||||
uint32_t index;
|
||||
SafeNumeric<uint32_t> index;
|
||||
C *instance;
|
||||
U userdata;
|
||||
void (C::*method)(uint32_t, U);
|
||||
|
@ -56,7 +56,7 @@ template <class T>
|
|||
void process_array_thread(void *ud) {
|
||||
T &data = *(T *)ud;
|
||||
while (true) {
|
||||
uint32_t index = atomic_increment(&data.index);
|
||||
uint32_t index = data.index.increment();
|
||||
if (index >= data.elements) {
|
||||
break;
|
||||
}
|
||||
|
@ -70,9 +70,9 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
|
|||
data.method = p_method;
|
||||
data.instance = p_instance;
|
||||
data.userdata = p_userdata;
|
||||
data.index = 0;
|
||||
data.index.set(0);
|
||||
data.elements = p_elements;
|
||||
data.process(data.index); //process first, let threads increment for next
|
||||
data.process(0); //process first, let threads increment for next
|
||||
|
||||
int thread_count = OS::get_singleton()->get_processor_count();
|
||||
Thread *threads = memnew_arr(Thread, thread_count);
|
||||
|
|
|
@ -45,6 +45,9 @@ class CharString;
|
|||
template <class T, class V>
|
||||
class VMap;
|
||||
|
||||
// CowData is relying on this to be true
|
||||
static_assert(sizeof(SafeNumeric<uint32_t>) == sizeof(uint32_t));
|
||||
|
||||
template <class T>
|
||||
class CowData {
|
||||
template <class TV>
|
||||
|
@ -60,12 +63,12 @@ private:
|
|||
|
||||
// internal helpers
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_refcount() const {
|
||||
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<uint32_t *>(_ptr) - 2;
|
||||
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_size() const {
|
||||
|
@ -192,9 +195,9 @@ void CowData<T>::_unref(void *p_data) {
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t *refc = _get_refcount();
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
if (atomic_decrement(refc) > 0) {
|
||||
if (refc->decrement() > 0) {
|
||||
return; // still in use
|
||||
}
|
||||
// clean up
|
||||
|
@ -219,15 +222,15 @@ void CowData<T>::_copy_on_write() {
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t *refc = _get_refcount();
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
if (unlikely(*refc > 1)) {
|
||||
if (unlikely(refc->get() > 1)) {
|
||||
/* in use by more than me */
|
||||
uint32_t current_size = *_get_size();
|
||||
|
||||
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
|
||||
|
||||
*(mem_new - 2) = 1; //refcount
|
||||
reinterpret_cast<SafeNumeric<uint32_t> *>(mem_new - 2)->set(1); //refcount
|
||||
*(mem_new - 1) = current_size; //size
|
||||
|
||||
T *_data = (T *)(mem_new);
|
||||
|
@ -278,7 +281,7 @@ Error CowData<T>::resize(int p_size) {
|
|||
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
|
||||
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
|
||||
*(ptr - 1) = 0; //size, currently none
|
||||
*(ptr - 2) = 1; //refcount
|
||||
reinterpret_cast<SafeNumeric<uint32_t> *>(ptr - 2)->set(1); //refcount
|
||||
|
||||
_ptr = (T *)ptr;
|
||||
|
||||
|
@ -359,7 +362,7 @@ void CowData<T>::_ref(const CowData &p_from) {
|
|||
return; //nothing to do
|
||||
}
|
||||
|
||||
if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference
|
||||
if (p_from._get_refcount()->increment() > 0) { // could reference
|
||||
_ptr = p_from._ptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,4 +30,4 @@
|
|||
|
||||
#include "rid_owner.h"
|
||||
|
||||
volatile uint64_t RID_AllocBase::base_id = 1;
|
||||
SafeNumeric<uint64_t> RID_AllocBase::base_id{ 1 };
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include <typeinfo>
|
||||
|
||||
class RID_AllocBase {
|
||||
static volatile uint64_t base_id;
|
||||
static SafeNumeric<uint64_t> base_id;
|
||||
|
||||
protected:
|
||||
static RID _make_from_id(uint64_t p_id) {
|
||||
|
@ -54,7 +54,7 @@ protected:
|
|||
}
|
||||
|
||||
static uint64_t _gen_id() {
|
||||
return atomic_increment(&base_id);
|
||||
return base_id.increment();
|
||||
}
|
||||
|
||||
static RID _gen_rid() {
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* safe_refcount.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "safe_refcount.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/* Implementation for MSVC-Windows */
|
||||
|
||||
// don't pollute my namespace!
|
||||
#include <windows.h>
|
||||
|
||||
#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \
|
||||
/* try to increment until it actually works */ \
|
||||
/* taken from boost */ \
|
||||
while (true) { \
|
||||
m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
|
||||
if (tmp == 0) { \
|
||||
return 0; /* if zero, can't add to it anymore */ \
|
||||
} \
|
||||
if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) { \
|
||||
return tmp + 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \
|
||||
while (true) { \
|
||||
m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
|
||||
if (tmp >= m_val) { \
|
||||
return tmp; /* already greater, or equal */ \
|
||||
} \
|
||||
if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) { \
|
||||
return m_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw) {
|
||||
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
|
||||
return InterlockedDecrement((LONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
|
||||
return InterlockedIncrement((LONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return InterlockedAdd((LONG volatile *)pw, val);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw) {
|
||||
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
|
||||
return InterlockedDecrement64((LONGLONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
|
||||
return InterlockedIncrement64((LONGLONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return InterlockedAdd64((LONGLONG volatile *)pw, val);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t);
|
||||
}
|
||||
|
||||
// The actual advertised functions; they'll call the right implementation
|
||||
|
||||
uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
|
||||
return _atomic_conditional_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_decrement(volatile uint32_t *pw) {
|
||||
return _atomic_decrement_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_increment(volatile uint32_t *pw) {
|
||||
return _atomic_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_sub_impl(pw, val);
|
||||
}
|
||||
|
||||
uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_add_impl(pw, val);
|
||||
}
|
||||
|
||||
uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_exchange_if_greater_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
|
||||
return _atomic_conditional_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_decrement(volatile uint64_t *pw) {
|
||||
return _atomic_decrement_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_increment(volatile uint64_t *pw) {
|
||||
return _atomic_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_sub_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_add_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_exchange_if_greater_impl(pw, val);
|
||||
}
|
||||
#endif
|
|
@ -31,167 +31,281 @@
|
|||
#ifndef SAFE_REFCOUNT_H
|
||||
#define SAFE_REFCOUNT_H
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "platform_config.h"
|
||||
|
||||
// Atomic functions, these are used for multithread safe reference counters!
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#ifdef NO_THREADS
|
||||
#include <atomic>
|
||||
|
||||
/* Bogus implementation unaware of multiprocessing */
|
||||
// Design goals for these classes:
|
||||
// - No automatic conversions or arithmetic operators,
|
||||
// to keep explicit the use of atomics everywhere.
|
||||
// - Using acquire-release semantics, even to set the first value.
|
||||
// The first value may be set relaxedly in many cases, but adding the distinction
|
||||
// between relaxed and unrelaxed operation to the interface would make it needlessly
|
||||
// flexible. There's negligible waste in having release semantics for the initial
|
||||
// value and, as an important benefit, you can be sure the value is properly synchronized
|
||||
// even with threads that are already running.
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
|
||||
if (*pw == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*pw)++;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
|
||||
(*pw)--;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
|
||||
(*pw)++;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
|
||||
(*pw) -= val;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
|
||||
(*pw) += val;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
|
||||
if (val > *pw) {
|
||||
*pw = val;
|
||||
}
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
/* Implementation for GCC & Clang */
|
||||
|
||||
// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes.
|
||||
// Clang states it supports GCC atomic builtins.
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
|
||||
while (true) {
|
||||
T tmp = static_cast<T const volatile &>(*pw);
|
||||
if (tmp == 0) {
|
||||
return 0; // if zero, can't add to it anymore
|
||||
}
|
||||
if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp) {
|
||||
return tmp + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
|
||||
return __sync_sub_and_fetch(pw, 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
|
||||
return __sync_add_and_fetch(pw, 1);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
|
||||
return __sync_sub_and_fetch(pw, val);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
|
||||
return __sync_add_and_fetch(pw, val);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
|
||||
while (true) {
|
||||
T tmp = static_cast<T const volatile &>(*pw);
|
||||
if (tmp >= val) {
|
||||
return tmp; // already greater, or equal
|
||||
}
|
||||
if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
// For MSVC use a separate compilation unit to prevent windows.h from polluting
|
||||
// the global namespace.
|
||||
uint32_t atomic_conditional_increment(volatile uint32_t *pw);
|
||||
uint32_t atomic_decrement(volatile uint32_t *pw);
|
||||
uint32_t atomic_increment(volatile uint32_t *pw);
|
||||
uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
|
||||
uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
|
||||
uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
|
||||
|
||||
uint64_t atomic_conditional_increment(volatile uint64_t *pw);
|
||||
uint64_t atomic_decrement(volatile uint64_t *pw);
|
||||
uint64_t atomic_increment(volatile uint64_t *pw);
|
||||
uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
|
||||
uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
|
||||
uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
|
||||
|
||||
#else
|
||||
//no threads supported?
|
||||
#error Must provide atomic functions for this platform or compiler!
|
||||
#endif
|
||||
|
||||
struct SafeRefCount {
|
||||
uint32_t count = 0;
|
||||
class SafeNumeric {
|
||||
std::atomic<T> value;
|
||||
|
||||
public:
|
||||
// destroy() is called when weak_count_ drops to zero.
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel) + 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
while (true) {
|
||||
T tmp = value.load(std::memory_order_acquire);
|
||||
if (tmp >= p_value) {
|
||||
return tmp; // already greater, or equal
|
||||
}
|
||||
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
|
||||
return p_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
while (true) {
|
||||
T c = value.load(std::memory_order_acquire);
|
||||
if (c == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
|
||||
return c + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
|
||||
set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
std::atomic_bool flag;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
|
||||
set_to(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
SafeNumeric<uint32_t> count;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
|
||||
return atomic_conditional_increment(&count) != 0;
|
||||
return count.conditional_increment() != 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
|
||||
return atomic_conditional_increment(&count);
|
||||
return count.conditional_increment();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
|
||||
return atomic_decrement(&count) == 0;
|
||||
return count.decrement() == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
|
||||
return atomic_decrement(&count);
|
||||
return count.decrement();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const { // nothrow
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count.get();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
|
||||
count.set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
class SafeNumeric {
|
||||
protected:
|
||||
T value;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return ++value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value++;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return --value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value--;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value += p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
T old = value;
|
||||
value += p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value -= p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
T old = value;
|
||||
value -= p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
if (value < p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
if (value != 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ++value;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
|
||||
value(p_value) {
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
protected:
|
||||
bool flag;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag = true;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
|
||||
flag(p_value) {}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
uint32_t count = 0;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
if (count != 0) {
|
||||
++count;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
if (count != 0) {
|
||||
return ++count;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
return --count == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
return --count;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -200,4 +314,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SAFE_REFCOUNT_H
|
||||
|
|
|
@ -155,7 +155,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) {
|
|||
|
||||
preview->playback->stop();
|
||||
|
||||
preview->generating = false;
|
||||
preview->generating.clear();
|
||||
}
|
||||
|
||||
Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<AudioStream> &p_stream) {
|
||||
|
@ -172,7 +172,7 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
|
|||
Preview *preview = &previews[p_stream->get_instance_id()];
|
||||
preview->base_stream = p_stream;
|
||||
preview->playback = preview->base_stream->instance_playback();
|
||||
preview->generating = true;
|
||||
preview->generating.set();
|
||||
preview->id = p_stream->get_instance_id();
|
||||
|
||||
float len_s = preview->base_stream->get_length();
|
||||
|
@ -217,7 +217,7 @@ void AudioStreamPreviewGenerator::_notification(int p_what) {
|
|||
if (p_what == NOTIFICATION_PROCESS) {
|
||||
List<ObjectID> to_erase;
|
||||
for (Map<ObjectID, Preview>::Element *E = previews.front(); E; E = E->next()) {
|
||||
if (!E->get().generating) {
|
||||
if (!E->get().generating.is_set()) {
|
||||
if (E->get().thread) {
|
||||
E->get().thread->wait_to_finish();
|
||||
memdelete(E->get().thread);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define AUDIO_STREAM_PREVIEW_H
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
|
||||
|
@ -60,9 +61,20 @@ class AudioStreamPreviewGenerator : public Node {
|
|||
Ref<AudioStreamPreview> preview;
|
||||
Ref<AudioStream> base_stream;
|
||||
Ref<AudioStreamPlayback> playback;
|
||||
volatile bool generating = false;
|
||||
SafeFlag generating;
|
||||
ObjectID id;
|
||||
Thread *thread = nullptr;
|
||||
|
||||
// Needed for the bookkeeping of the Map
|
||||
Preview &operator=(const Preview &p_rhs) {
|
||||
preview = p_rhs.preview;
|
||||
base_stream = p_rhs.base_stream;
|
||||
playback = p_rhs.playback;
|
||||
generating.set_to(generating.is_set());
|
||||
id = p_rhs.id;
|
||||
thread = p_rhs.thread;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Map<ObjectID, Preview> previews;
|
||||
|
|
|
@ -1413,11 +1413,11 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
|
|||
}
|
||||
|
||||
void EditorFileSystem::update_script_classes() {
|
||||
if (!update_script_classes_queued) {
|
||||
if (!update_script_classes_queued.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_script_classes_queued = false;
|
||||
update_script_classes_queued.clear();
|
||||
ScriptServer::global_classes_clear();
|
||||
if (get_filesystem()) {
|
||||
_scan_script_classes(get_filesystem());
|
||||
|
@ -1436,11 +1436,11 @@ void EditorFileSystem::update_script_classes() {
|
|||
}
|
||||
|
||||
void EditorFileSystem::_queue_update_script_classes() {
|
||||
if (update_script_classes_queued) {
|
||||
if (update_script_classes_queued.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_script_classes_queued = true;
|
||||
update_script_classes_queued.set();
|
||||
call_deferred("update_script_classes");
|
||||
}
|
||||
|
||||
|
@ -2091,7 +2091,7 @@ EditorFileSystem::EditorFileSystem() {
|
|||
memdelete(da);
|
||||
|
||||
scan_total = 0;
|
||||
update_script_classes_queued = false;
|
||||
update_script_classes_queued.clear();
|
||||
first_scan = true;
|
||||
scan_changes_pending = false;
|
||||
revalidate_import_files = false;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/os/dir_access.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/templates/set.h"
|
||||
#include "scene/main/node.h"
|
||||
class FileAccess;
|
||||
|
@ -220,7 +221,7 @@ class EditorFileSystem : public Node {
|
|||
};
|
||||
|
||||
void _scan_script_classes(EditorFileSystemDirectory *p_dir);
|
||||
volatile bool update_script_classes_queued;
|
||||
SafeFlag update_script_classes_queued;
|
||||
void _queue_update_script_classes();
|
||||
|
||||
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
|
||||
|
|
|
@ -5565,7 +5565,8 @@ static void _execute_thread(void *p_ud) {
|
|||
eta->exitcode = err;
|
||||
}
|
||||
|
||||
eta->done = true;
|
||||
eta->done.set();
|
||||
;
|
||||
}
|
||||
|
||||
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
|
||||
|
@ -5579,13 +5580,12 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
|
|||
eta.path = p_path;
|
||||
eta.args = p_arguments;
|
||||
eta.exitcode = 255;
|
||||
eta.done = false;
|
||||
|
||||
int prev_len = 0;
|
||||
|
||||
eta.execute_output_thread.start(_execute_thread, &eta);
|
||||
|
||||
while (!eta.done) {
|
||||
while (!eta.done.is_set()) {
|
||||
{
|
||||
MutexLock lock(eta.execute_output_mutex);
|
||||
if (prev_len != eta.output.length()) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef EDITOR_NODE_H
|
||||
#define EDITOR_NODE_H
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "editor/editor_data.h"
|
||||
#include "editor/editor_export.h"
|
||||
#include "editor/editor_folding.h"
|
||||
|
@ -111,7 +112,7 @@ public:
|
|||
Thread execute_output_thread;
|
||||
Mutex execute_output_mutex;
|
||||
int exitcode = 0;
|
||||
volatile bool done = false;
|
||||
SafeFlag done;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -206,8 +206,8 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
|
|||
}
|
||||
|
||||
void EditorResourcePreview::_thread() {
|
||||
exited = false;
|
||||
while (!exit) {
|
||||
exited.clear();
|
||||
while (!exit.is_set()) {
|
||||
preview_sem.wait();
|
||||
preview_mutex.lock();
|
||||
|
||||
|
@ -326,7 +326,7 @@ void EditorResourcePreview::_thread() {
|
|||
preview_mutex.unlock();
|
||||
}
|
||||
}
|
||||
exited = true;
|
||||
exited.set();
|
||||
}
|
||||
|
||||
void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
|
||||
|
@ -430,9 +430,9 @@ void EditorResourcePreview::start() {
|
|||
|
||||
void EditorResourcePreview::stop() {
|
||||
if (thread.is_started()) {
|
||||
exit = true;
|
||||
exit.set();
|
||||
preview_sem.post();
|
||||
while (!exited) {
|
||||
while (!exited.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10000);
|
||||
RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
|
||||
}
|
||||
|
@ -443,8 +443,6 @@ void EditorResourcePreview::stop() {
|
|||
EditorResourcePreview::EditorResourcePreview() {
|
||||
singleton = this;
|
||||
order = 0;
|
||||
exit = false;
|
||||
exited = false;
|
||||
}
|
||||
|
||||
EditorResourcePreview::~EditorResourcePreview() {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
|
@ -71,8 +72,8 @@ class EditorResourcePreview : public Node {
|
|||
Mutex preview_mutex;
|
||||
Semaphore preview_sem;
|
||||
Thread thread;
|
||||
volatile bool exit;
|
||||
volatile bool exited;
|
||||
SafeFlag exit;
|
||||
SafeFlag exited;
|
||||
|
||||
struct Item {
|
||||
Ref<Texture2D> preview;
|
||||
|
|
|
@ -301,7 +301,7 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorMaterialPreviewPlugin::_bind_methods() {
|
||||
|
@ -325,10 +325,10 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Si
|
|||
|
||||
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
@ -677,7 +677,7 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorMeshPreviewPlugin::_bind_methods() {
|
||||
|
@ -714,10 +714,10 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
|
|||
|
||||
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
@ -792,7 +792,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorFontPreviewPlugin::_bind_methods() {
|
||||
|
@ -883,11 +883,11 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
|
|||
|
||||
font->draw_string(canvas_item, pos, sample, HALIGN_LEFT, -1.f, 50, Color(1, 1, 1));
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include "editor/editor_resource_preview.h"
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
void post_process_preview(Ref<Image> p_image);
|
||||
|
||||
class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
|
@ -90,7 +92,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID light2;
|
||||
RID light_instance2;
|
||||
RID camera;
|
||||
mutable volatile bool preview_done = false;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
@ -134,7 +136,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID light2;
|
||||
RID light_instance2;
|
||||
RID camera;
|
||||
mutable volatile bool preview_done = false;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
@ -156,7 +158,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID viewport_texture;
|
||||
RID canvas;
|
||||
RID canvas_item;
|
||||
mutable volatile bool preview_done = false;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/os/os.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/string/print_string.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
||||
#include <ConvectionKernels.h>
|
||||
|
||||
|
@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue {
|
|||
CVTTCompressionJobParams job_params;
|
||||
const CVTTCompressionRowTask *job_tasks;
|
||||
uint32_t num_tasks = 0;
|
||||
uint32_t current_task = 0;
|
||||
SafeNumeric<uint32_t> current_task;
|
||||
};
|
||||
|
||||
static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
|
||||
|
@ -131,7 +132,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const
|
|||
static void _digest_job_queue(void *p_job_queue) {
|
||||
CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
|
||||
|
||||
for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) {
|
||||
for (uint32_t next_task = job_queue->current_task.increment(); next_task <= job_queue->num_tasks; next_task = job_queue->current_task.increment()) {
|
||||
_digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]);
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +264,7 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann
|
|||
const CVTTCompressionRowTask *tasks_rb = tasks.ptr();
|
||||
|
||||
job_queue.job_tasks = &tasks_rb[0];
|
||||
job_queue.current_task = 0;
|
||||
job_queue.current_task.set(0);
|
||||
job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
|
||||
|
||||
for (int i = 0; i < num_job_threads; i++) {
|
||||
|
|
|
@ -1670,7 +1670,7 @@ void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeSc
|
|||
MutexLock lock(mutex);
|
||||
libs_to_init.insert(lib);
|
||||
scripts_to_register.insert(script);
|
||||
has_objects_to_register = true;
|
||||
has_objects_to_register.set();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1759,7 +1759,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
|
|||
|
||||
void NativeScriptLanguage::frame() {
|
||||
#ifndef NO_THREADS
|
||||
if (has_objects_to_register) {
|
||||
if (has_objects_to_register.is_set()) {
|
||||
MutexLock lock(mutex);
|
||||
for (Set<Ref<GDNativeLibrary>>::Element *L = libs_to_init.front(); L; L = L->next()) {
|
||||
init_library(L->get());
|
||||
|
@ -1769,7 +1769,7 @@ void NativeScriptLanguage::frame() {
|
|||
register_script(S->get());
|
||||
}
|
||||
scripts_to_register.clear();
|
||||
has_objects_to_register = false;
|
||||
has_objects_to_register.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "core/os/thread_safe.h"
|
||||
#include "core/templates/oa_hash_map.h"
|
||||
#include "core/templates/ordered_hash_map.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/templates/self_list.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
|
@ -262,7 +263,7 @@ private:
|
|||
#ifndef NO_THREADS
|
||||
Set<Ref<GDNativeLibrary>> libs_to_init;
|
||||
Set<NativeScript *> scripts_to_register;
|
||||
volatile bool has_objects_to_register = false; // so that we don't lock mutex every frame - it's rarely needed
|
||||
SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
|
||||
void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/ring_buffer.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/resources/video_stream.h"
|
||||
#include "servers/audio_server.h"
|
||||
|
||||
|
@ -113,7 +114,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
|
|||
bool thread_eof = false;
|
||||
Semaphore *thread_sem;
|
||||
Thread thread;
|
||||
volatile bool thread_exit = false;
|
||||
SafeFlag thread_exit;
|
||||
|
||||
static void _streaming_thread(void *ud);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "core/os/dir_access.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/version.h"
|
||||
#include "drivers/png/png_driver_common.h"
|
||||
#include "editor/editor_export.h"
|
||||
|
@ -264,38 +265,38 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||
Vector<PluginConfigAndroid> plugins;
|
||||
String last_plugin_names;
|
||||
uint64_t last_custom_build_time = 0;
|
||||
volatile bool plugins_changed;
|
||||
SafeFlag plugins_changed;
|
||||
Mutex plugins_lock;
|
||||
Vector<Device> devices;
|
||||
volatile bool devices_changed;
|
||||
SafeFlag devices_changed;
|
||||
Mutex device_lock;
|
||||
Thread check_for_changes_thread;
|
||||
volatile bool quit_request;
|
||||
SafeFlag quit_request;
|
||||
|
||||
static void _check_for_changes_poll_thread(void *ud) {
|
||||
EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
|
||||
|
||||
while (!ea->quit_request) {
|
||||
while (!ea->quit_request.is_set()) {
|
||||
// Check for plugins updates
|
||||
{
|
||||
// Nothing to do if we already know the plugins have changed.
|
||||
if (!ea->plugins_changed) {
|
||||
if (!ea->plugins_changed.is_set()) {
|
||||
Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
|
||||
|
||||
MutexLock lock(ea->plugins_lock);
|
||||
|
||||
if (ea->plugins.size() != loaded_plugins.size()) {
|
||||
ea->plugins_changed = true;
|
||||
ea->plugins_changed.set();
|
||||
} else {
|
||||
for (int i = 0; i < ea->plugins.size(); i++) {
|
||||
if (ea->plugins[i].name != loaded_plugins[i].name) {
|
||||
ea->plugins_changed = true;
|
||||
ea->plugins_changed.set();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ea->plugins_changed) {
|
||||
if (ea->plugins_changed.is_set()) {
|
||||
ea->plugins = loaded_plugins;
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +410,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||
}
|
||||
|
||||
ea->devices = ndevices;
|
||||
ea->devices_changed = true;
|
||||
ea->devices_changed.set();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +419,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||
uint64_t time = OS::get_singleton()->get_ticks_usec();
|
||||
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
|
||||
OS::get_singleton()->delay_usec(1000 * sleep);
|
||||
if (ea->quit_request) {
|
||||
if (ea->quit_request.is_set()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1642,7 +1643,7 @@ public:
|
|||
print_verbose("Found Android plugin " + plugins_configs[i].name);
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false));
|
||||
}
|
||||
plugins_changed = false;
|
||||
plugins_changed.clear();
|
||||
|
||||
Vector<String> abis = get_abis();
|
||||
for (int i = 0; i < abis.size(); ++i) {
|
||||
|
@ -1712,19 +1713,19 @@ public:
|
|||
}
|
||||
|
||||
virtual bool should_update_export_options() override {
|
||||
bool export_options_changed = plugins_changed;
|
||||
bool export_options_changed = plugins_changed.is_set();
|
||||
if (export_options_changed) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
plugins_changed = false;
|
||||
plugins_changed.clear();
|
||||
}
|
||||
return export_options_changed;
|
||||
}
|
||||
|
||||
virtual bool poll_export() override {
|
||||
bool dc = devices_changed;
|
||||
bool dc = devices_changed.is_set();
|
||||
if (dc) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
devices_changed = false;
|
||||
devices_changed.clear();
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
|
@ -2913,14 +2914,13 @@ public:
|
|||
run_icon.instance();
|
||||
run_icon->create_from_image(img);
|
||||
|
||||
devices_changed = true;
|
||||
plugins_changed = true;
|
||||
quit_request = false;
|
||||
devices_changed.set();
|
||||
plugins_changed.set();
|
||||
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
|
||||
}
|
||||
|
||||
~EditorExportPlatformAndroid() {
|
||||
quit_request = true;
|
||||
quit_request.set();
|
||||
check_for_changes_thread.wait_to_finish();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -187,14 +187,14 @@ String GodotIOJavaWrapper::get_system_dir(int p_dir) {
|
|||
}
|
||||
}
|
||||
|
||||
// volatile because it can be changed from non-main thread and we need to
|
||||
// SafeNumeric because it can be changed from non-main thread and we need to
|
||||
// ensure the change is immediately visible to other threads.
|
||||
static volatile int virtual_keyboard_height;
|
||||
static SafeNumeric<int> virtual_keyboard_height;
|
||||
|
||||
int GodotIOJavaWrapper::get_vk_height() {
|
||||
return virtual_keyboard_height;
|
||||
return virtual_keyboard_height.get();
|
||||
}
|
||||
|
||||
void GodotIOJavaWrapper::set_vk_height(int p_height) {
|
||||
virtual_keyboard_height = p_height;
|
||||
virtual_keyboard_height.set(p_height);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "core/io/zip_io.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/version.h"
|
||||
#include "editor/editor_export.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
@ -56,9 +57,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
|
|||
Ref<ImageTexture> logo;
|
||||
|
||||
// Plugins
|
||||
volatile bool plugins_changed;
|
||||
SafeFlag plugins_changed;
|
||||
Thread check_for_changes_thread;
|
||||
volatile bool quit_request;
|
||||
SafeFlag quit_request;
|
||||
Mutex plugins_lock;
|
||||
Vector<PluginConfigIOS> plugins;
|
||||
|
||||
|
@ -141,19 +142,19 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
|
|||
static void _check_for_changes_poll_thread(void *ud) {
|
||||
EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud;
|
||||
|
||||
while (!ea->quit_request) {
|
||||
while (!ea->quit_request.is_set()) {
|
||||
// Nothing to do if we already know the plugins have changed.
|
||||
if (!ea->plugins_changed) {
|
||||
if (!ea->plugins_changed.is_set()) {
|
||||
MutexLock lock(ea->plugins_lock);
|
||||
|
||||
Vector<PluginConfigIOS> loaded_plugins = get_plugins();
|
||||
|
||||
if (ea->plugins.size() != loaded_plugins.size()) {
|
||||
ea->plugins_changed = true;
|
||||
ea->plugins_changed.set();
|
||||
} else {
|
||||
for (int i = 0; i < ea->plugins.size(); i++) {
|
||||
if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
|
||||
ea->plugins_changed = true;
|
||||
ea->plugins_changed.set();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +166,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
|
|||
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
|
||||
OS::get_singleton()->delay_usec(300000);
|
||||
|
||||
if (ea->quit_request) {
|
||||
if (ea->quit_request.is_set()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -182,10 +183,10 @@ public:
|
|||
virtual Ref<Texture2D> get_logo() const override { return logo; }
|
||||
|
||||
virtual bool should_update_export_options() override {
|
||||
bool export_options_changed = plugins_changed;
|
||||
bool export_options_changed = plugins_changed.is_set();
|
||||
if (export_options_changed) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
plugins_changed = false;
|
||||
plugins_changed.clear();
|
||||
}
|
||||
return export_options_changed;
|
||||
}
|
||||
|
@ -364,7 +365,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
|
|||
for (int i = 0; i < found_plugins.size(); i++) {
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false));
|
||||
}
|
||||
plugins_changed = false;
|
||||
plugins_changed.clear();
|
||||
plugins = found_plugins;
|
||||
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
|
||||
|
@ -1967,14 +1968,13 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() {
|
|||
logo.instance();
|
||||
logo->create_from_image(img);
|
||||
|
||||
plugins_changed = true;
|
||||
quit_request = false;
|
||||
plugins_changed.set();
|
||||
|
||||
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
|
||||
}
|
||||
|
||||
EditorExportPlatformIOS::~EditorExportPlatformIOS() {
|
||||
quit_request = true;
|
||||
quit_request.set();
|
||||
check_for_changes_thread.wait_to_finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -2697,7 +2697,7 @@ bool DisplayServerX11::_wait_for_events() const {
|
|||
}
|
||||
|
||||
void DisplayServerX11::_poll_events() {
|
||||
while (!events_thread_done) {
|
||||
while (!events_thread_done.is_set()) {
|
||||
_wait_for_events();
|
||||
|
||||
// Process events from the queue.
|
||||
|
@ -4279,7 +4279,7 @@ DisplayServerX11::~DisplayServerX11() {
|
|||
_clipboard_transfer_ownership(XA_PRIMARY, x11_main_window);
|
||||
_clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window);
|
||||
|
||||
events_thread_done = true;
|
||||
events_thread_done.set();
|
||||
events_thread.wait_to_finish();
|
||||
|
||||
//destroy all windows
|
||||
|
|
|
@ -253,7 +253,7 @@ class DisplayServerX11 : public DisplayServer {
|
|||
|
||||
mutable Mutex events_mutex;
|
||||
Thread events_thread;
|
||||
bool events_thread_done = false;
|
||||
SafeFlag events_thread_done;
|
||||
LocalVector<XEvent> polled_events;
|
||||
static void _poll_events_thread(void *ud);
|
||||
bool _wait_for_events() const;
|
||||
|
|
|
@ -87,7 +87,7 @@ JoypadLinux::JoypadLinux(Input *in) {
|
|||
}
|
||||
|
||||
JoypadLinux::~JoypadLinux() {
|
||||
exit_monitor = true;
|
||||
exit_monitor.set();
|
||||
joy_thread.wait_to_finish();
|
||||
close_joypad();
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
|
|||
udev_monitor_enable_receiving(mon);
|
||||
int fd = udev_monitor_get_fd(mon);
|
||||
|
||||
while (!exit_monitor) {
|
||||
while (!exit_monitor.is_set()) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
|
@ -197,7 +197,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
|
|||
#endif
|
||||
|
||||
void JoypadLinux::monitor_joypads() {
|
||||
while (!exit_monitor) {
|
||||
while (!exit_monitor.is_set()) {
|
||||
{
|
||||
MutexLock lock(joy_mutex);
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ private:
|
|||
#ifdef UDEV_ENABLED
|
||||
bool use_udev = false;
|
||||
#endif
|
||||
bool exit_monitor = false;
|
||||
SafeFlag exit_monitor;
|
||||
Mutex joy_mutex;
|
||||
Thread joy_thread;
|
||||
Input *input = nullptr;
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
#include "scene/main/window.h"
|
||||
|
||||
void AudioStreamPlayer2D::_mix_audio() {
|
||||
if (!stream_playback.is_valid() || !active ||
|
||||
if (!stream_playback.is_valid() || !active.is_set() ||
|
||||
(stream_paused && !stream_paused_fade_out)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (setseek >= 0.0) {
|
||||
stream_playback->start(setseek);
|
||||
setseek = -1.0; //reset seek
|
||||
if (setseek.get() >= 0.0) {
|
||||
stream_playback->start(setseek.get());
|
||||
setseek.set(-1.0); //reset seek
|
||||
}
|
||||
|
||||
//get data
|
||||
|
@ -57,7 +57,8 @@ void AudioStreamPlayer2D::_mix_audio() {
|
|||
stream_playback->mix(buffer, pitch_scale, buffer_size);
|
||||
|
||||
//write all outputs
|
||||
for (int i = 0; i < output_count; i++) {
|
||||
int oc = output_count.get();
|
||||
for (int i = 0; i < oc; i++) {
|
||||
Output current = outputs[i];
|
||||
|
||||
//see if current output exists, to keep volume ramp
|
||||
|
@ -130,14 +131,14 @@ void AudioStreamPlayer2D::_mix_audio() {
|
|||
prev_outputs[i] = current;
|
||||
}
|
||||
|
||||
prev_output_count = output_count;
|
||||
prev_output_count = oc;
|
||||
|
||||
//stream is no longer active, disable this.
|
||||
if (!stream_playback->is_playing()) {
|
||||
active = false;
|
||||
active.clear();
|
||||
}
|
||||
|
||||
output_ready = false;
|
||||
output_ready.clear();
|
||||
stream_paused_fade_in = false;
|
||||
stream_paused_fade_out = false;
|
||||
}
|
||||
|
@ -168,7 +169,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
|
|||
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
||||
//update anything related to position first, if possible of course
|
||||
|
||||
if (!output_ready) {
|
||||
if (!output_ready.is_set()) {
|
||||
List<Viewport *> viewports;
|
||||
Ref<World2D> world_2d = get_world_2d();
|
||||
ERR_FAIL_COND(world_2d.is_null());
|
||||
|
@ -240,19 +241,19 @@ void AudioStreamPlayer2D::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
output_count = new_output_count;
|
||||
output_ready = true;
|
||||
output_count.set(new_output_count);
|
||||
output_ready.set();
|
||||
}
|
||||
|
||||
//start playing if requested
|
||||
if (setplay >= 0.0) {
|
||||
setseek = setplay;
|
||||
active = true;
|
||||
setplay = -1;
|
||||
if (setplay.get() >= 0.0) {
|
||||
setseek.set(setplay.get());
|
||||
active.set();
|
||||
setplay.set(-1);
|
||||
}
|
||||
|
||||
//stop playing if no longer active
|
||||
if (!active) {
|
||||
if (!active.is_set()) {
|
||||
set_physics_process_internal(false);
|
||||
emit_signal("finished");
|
||||
}
|
||||
|
@ -267,8 +268,8 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
|
|||
if (stream_playback.is_valid()) {
|
||||
stream_playback.unref();
|
||||
stream.unref();
|
||||
active = false;
|
||||
setseek = -1;
|
||||
active.clear();
|
||||
setseek.set(-1);
|
||||
}
|
||||
|
||||
if (p_stream.is_valid()) {
|
||||
|
@ -311,29 +312,29 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
|
|||
}
|
||||
|
||||
if (stream_playback.is_valid()) {
|
||||
setplay = p_from_pos;
|
||||
output_ready = false;
|
||||
setplay.set(p_from_pos);
|
||||
output_ready.clear();
|
||||
set_physics_process_internal(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer2D::seek(float p_seconds) {
|
||||
if (stream_playback.is_valid()) {
|
||||
setseek = p_seconds;
|
||||
setseek.set(p_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer2D::stop() {
|
||||
if (stream_playback.is_valid()) {
|
||||
active = false;
|
||||
active.clear();
|
||||
set_physics_process_internal(false);
|
||||
setplay = -1;
|
||||
setplay.set(-1);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioStreamPlayer2D::is_playing() const {
|
||||
if (stream_playback.is_valid()) {
|
||||
return active || setplay >= 0;
|
||||
return active.is_set() || setplay.get() >= 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -341,8 +342,9 @@ bool AudioStreamPlayer2D::is_playing() const {
|
|||
|
||||
float AudioStreamPlayer2D::get_playback_position() {
|
||||
if (stream_playback.is_valid()) {
|
||||
if (setseek >= 0.0) {
|
||||
return setseek;
|
||||
float ss = setseek.get();
|
||||
if (ss >= 0.0) {
|
||||
return ss;
|
||||
}
|
||||
return stream_playback->get_playback_position();
|
||||
}
|
||||
|
@ -383,7 +385,7 @@ void AudioStreamPlayer2D::_set_playing(bool p_enable) {
|
|||
}
|
||||
|
||||
bool AudioStreamPlayer2D::_is_active() const {
|
||||
return active;
|
||||
return active.is_set();
|
||||
}
|
||||
|
||||
void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef AUDIO_STREAM_PLAYER_2D_H
|
||||
#define AUDIO_STREAM_PLAYER_2D_H
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/2d/node_2d.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
#include "servers/audio_server.h"
|
||||
|
@ -52,8 +53,8 @@ private:
|
|||
};
|
||||
|
||||
Output outputs[MAX_OUTPUTS];
|
||||
volatile int output_count = 0;
|
||||
volatile bool output_ready = false;
|
||||
SafeNumeric<int> output_count;
|
||||
SafeFlag output_ready;
|
||||
|
||||
//these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
|
||||
Output prev_outputs[MAX_OUTPUTS];
|
||||
|
@ -63,9 +64,9 @@ private:
|
|||
Ref<AudioStream> stream;
|
||||
Vector<AudioFrame> mix_buffer;
|
||||
|
||||
volatile float setseek = -1.0;
|
||||
volatile bool active = false;
|
||||
volatile float setplay = -1.0;
|
||||
SafeNumeric<float> setseek{ -1.0 };
|
||||
SafeFlag active;
|
||||
SafeNumeric<float> setplay{ -1.0 };
|
||||
|
||||
float volume_db = 0.0;
|
||||
float pitch_scale = 1.0;
|
||||
|
|
|
@ -138,15 +138,15 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig
|
|||
}
|
||||
|
||||
void AudioStreamPlayer3D::_mix_audio() {
|
||||
if (!stream_playback.is_valid() || !active ||
|
||||
if (!stream_playback.is_valid() || !active.is_set() ||
|
||||
(stream_paused && !stream_paused_fade_out)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool started = false;
|
||||
if (setseek >= 0.0) {
|
||||
stream_playback->start(setseek);
|
||||
setseek = -1.0; //reset seek
|
||||
if (setseek.get() >= 0.0) {
|
||||
stream_playback->start(setseek.get());
|
||||
setseek.set(-1.0); //reset seek
|
||||
started = true;
|
||||
}
|
||||
|
||||
|
@ -160,14 +160,14 @@ void AudioStreamPlayer3D::_mix_audio() {
|
|||
}
|
||||
|
||||
// Mix if we're not paused or we're fading out
|
||||
if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
|
||||
if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
|
||||
float output_pitch_scale = 0.0;
|
||||
if (output_count) {
|
||||
if (output_count.get()) {
|
||||
//used for doppler, not realistic but good enough
|
||||
for (int i = 0; i < output_count; i++) {
|
||||
for (int i = 0; i < output_count.get(); i++) {
|
||||
output_pitch_scale += outputs[i].pitch_scale;
|
||||
}
|
||||
output_pitch_scale /= float(output_count);
|
||||
output_pitch_scale /= float(output_count.get());
|
||||
} else {
|
||||
output_pitch_scale = 1.0;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ void AudioStreamPlayer3D::_mix_audio() {
|
|||
}
|
||||
|
||||
//write all outputs
|
||||
for (int i = 0; i < output_count; i++) {
|
||||
for (int i = 0; i < output_count.get(); i++) {
|
||||
Output current = outputs[i];
|
||||
|
||||
//see if current output exists, to keep volume ramp
|
||||
|
@ -285,14 +285,14 @@ void AudioStreamPlayer3D::_mix_audio() {
|
|||
prev_outputs[i] = current;
|
||||
}
|
||||
|
||||
prev_output_count = output_count;
|
||||
prev_output_count = output_count.get();
|
||||
|
||||
//stream is no longer active, disable this.
|
||||
if (!stream_playback->is_playing()) {
|
||||
active = false;
|
||||
active.clear();
|
||||
}
|
||||
|
||||
output_ready = false;
|
||||
output_ready.clear();
|
||||
stream_paused_fade_in = false;
|
||||
stream_paused_fade_out = false;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
|
|||
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
||||
//update anything related to position first, if possible of course
|
||||
|
||||
if (!output_ready) {
|
||||
if (!output_ready.is_set()) {
|
||||
Vector3 linear_velocity;
|
||||
|
||||
//compute linear velocity for doppler
|
||||
|
@ -596,19 +596,19 @@ void AudioStreamPlayer3D::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
output_count = new_output_count;
|
||||
output_ready = true;
|
||||
output_count.set(new_output_count);
|
||||
output_ready.set();
|
||||
}
|
||||
|
||||
//start playing if requested
|
||||
if (setplay >= 0.0) {
|
||||
setseek = setplay;
|
||||
active = true;
|
||||
setplay = -1;
|
||||
if (setplay.get() >= 0.0) {
|
||||
setseek.set(setplay.get());
|
||||
active.set();
|
||||
setplay.set(-1);
|
||||
}
|
||||
|
||||
//stop playing if no longer active
|
||||
if (!active) {
|
||||
if (!active.is_set()) {
|
||||
set_physics_process_internal(false);
|
||||
emit_signal("finished");
|
||||
}
|
||||
|
@ -623,8 +623,8 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
|
|||
if (stream_playback.is_valid()) {
|
||||
stream_playback.unref();
|
||||
stream.unref();
|
||||
active = false;
|
||||
setseek = -1;
|
||||
active.clear();
|
||||
setseek.set(-1);
|
||||
}
|
||||
|
||||
if (p_stream.is_valid()) {
|
||||
|
@ -683,29 +683,29 @@ void AudioStreamPlayer3D::play(float p_from_pos) {
|
|||
}
|
||||
|
||||
if (stream_playback.is_valid()) {
|
||||
setplay = p_from_pos;
|
||||
output_ready = false;
|
||||
setplay.set(p_from_pos);
|
||||
output_ready.clear();
|
||||
set_physics_process_internal(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer3D::seek(float p_seconds) {
|
||||
if (stream_playback.is_valid()) {
|
||||
setseek = p_seconds;
|
||||
setseek.set(p_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer3D::stop() {
|
||||
if (stream_playback.is_valid()) {
|
||||
active = false;
|
||||
active.clear();
|
||||
set_physics_process_internal(false);
|
||||
setplay = -1;
|
||||
setplay.set(-1);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioStreamPlayer3D::is_playing() const {
|
||||
if (stream_playback.is_valid()) {
|
||||
return active || setplay >= 0;
|
||||
return active.is_set() || setplay.get() >= 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -713,8 +713,9 @@ bool AudioStreamPlayer3D::is_playing() const {
|
|||
|
||||
float AudioStreamPlayer3D::get_playback_position() {
|
||||
if (stream_playback.is_valid()) {
|
||||
if (setseek >= 0.0) {
|
||||
return setseek;
|
||||
float ss = setseek.get();
|
||||
if (ss >= 0.0) {
|
||||
return ss;
|
||||
}
|
||||
return stream_playback->get_playback_position();
|
||||
}
|
||||
|
@ -755,7 +756,7 @@ void AudioStreamPlayer3D::_set_playing(bool p_enable) {
|
|||
}
|
||||
|
||||
bool AudioStreamPlayer3D::_is_active() const {
|
||||
return active;
|
||||
return active.is_set();
|
||||
}
|
||||
|
||||
void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef AUDIO_STREAM_PLAYER_3D_H
|
||||
#define AUDIO_STREAM_PLAYER_3D_H
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/velocity_tracker_3d.h"
|
||||
#include "servers/audio/audio_filter_sw.h"
|
||||
|
@ -80,8 +81,8 @@ private:
|
|||
};
|
||||
|
||||
Output outputs[MAX_OUTPUTS];
|
||||
volatile int output_count = 0;
|
||||
volatile bool output_ready = false;
|
||||
SafeNumeric<int> output_count;
|
||||
SafeFlag output_ready;
|
||||
|
||||
//these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
|
||||
Output prev_outputs[MAX_OUTPUTS];
|
||||
|
@ -91,9 +92,9 @@ private:
|
|||
Ref<AudioStream> stream;
|
||||
Vector<AudioFrame> mix_buffer;
|
||||
|
||||
volatile float setseek = -1.0;
|
||||
volatile bool active = false;
|
||||
volatile float setplay = -1.0;
|
||||
SafeNumeric<float> setseek{ -1.0 };
|
||||
SafeFlag active;
|
||||
SafeNumeric<float> setplay{ -1.0 };
|
||||
|
||||
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
|
||||
float unit_db = 0.0;
|
||||
|
|
|
@ -1074,7 +1074,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
|
|||
ptr += 20;
|
||||
}
|
||||
|
||||
can_update = true;
|
||||
can_update.set();
|
||||
}
|
||||
|
||||
void CPUParticles3D::_set_redraw(bool p_redraw) {
|
||||
|
@ -1103,9 +1103,9 @@ void CPUParticles3D::_set_redraw(bool p_redraw) {
|
|||
void CPUParticles3D::_update_render_thread() {
|
||||
MutexLock lock(update_mutex);
|
||||
|
||||
if (can_update) {
|
||||
if (can_update.is_set()) {
|
||||
RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
|
||||
can_update = false; //wait for next time
|
||||
can_update.clear(); //wait for next time
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1167,7 +1167,7 @@ void CPUParticles3D::_notification(int p_what) {
|
|||
ptr += 20;
|
||||
}
|
||||
|
||||
can_update = true;
|
||||
can_update.set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1468,6 +1468,21 @@ CPUParticles3D::CPUParticles3D() {
|
|||
set_param(PARAM_HUE_VARIATION, 0);
|
||||
set_param(PARAM_ANIM_SPEED, 0);
|
||||
set_param(PARAM_ANIM_OFFSET, 0);
|
||||
set_emission_shape(EMISSION_SHAPE_POINT);
|
||||
set_emission_sphere_radius(1);
|
||||
set_emission_box_extents(Vector3(1, 1, 1));
|
||||
|
||||
set_gravity(Vector3(0, -9.8, 0));
|
||||
|
||||
for (int i = 0; i < PARAM_MAX; i++) {
|
||||
set_param_randomness(Parameter(i), 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
|
||||
particle_flags[i] = false;
|
||||
}
|
||||
|
||||
set_color(Color(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
CPUParticles3D::~CPUParticles3D() {
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define CPU_PARTICLES_H
|
||||
|
||||
#include "core/templates/rid.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/3d/visual_instance_3d.h"
|
||||
|
||||
class CPUParticles3D : public GeometryInstance3D {
|
||||
|
@ -142,7 +143,7 @@ private:
|
|||
|
||||
Transform inv_emission_transform;
|
||||
|
||||
volatile bool can_update = false;
|
||||
SafeFlag can_update;
|
||||
|
||||
DrawOrder draw_order = DRAW_ORDER_INDEX;
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ void AudioStreamPlayer::_mix_audio() {
|
|||
use_fadeout = false;
|
||||
}
|
||||
|
||||
if (!stream_playback.is_valid() || !active ||
|
||||
if (!stream_playback.is_valid() || !active.is_set() ||
|
||||
(stream_paused && !stream_paused_fade)) {
|
||||
return;
|
||||
}
|
||||
|
@ -112,24 +112,24 @@ void AudioStreamPlayer::_mix_audio() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (setstop) {
|
||||
if (setstop.is_set()) {
|
||||
_mix_internal(true);
|
||||
stream_playback->stop();
|
||||
setstop = false;
|
||||
setstop.clear();
|
||||
}
|
||||
|
||||
if (setseek >= 0.0 && !stop_has_priority) {
|
||||
if (setseek.get() >= 0.0 && !stop_has_priority.is_set()) {
|
||||
if (stream_playback->is_playing()) {
|
||||
//fade out to avoid pops
|
||||
_mix_internal(true);
|
||||
}
|
||||
|
||||
stream_playback->start(setseek);
|
||||
setseek = -1.0; //reset seek
|
||||
stream_playback->start(setseek.get());
|
||||
setseek.set(-1.0); //reset seek
|
||||
mix_volume_db = volume_db; //reset ramp
|
||||
}
|
||||
|
||||
stop_has_priority = false;
|
||||
stop_has_priority.clear();
|
||||
|
||||
_mix_internal(false);
|
||||
}
|
||||
|
@ -143,8 +143,8 @@ void AudioStreamPlayer::_notification(int p_what) {
|
|||
}
|
||||
|
||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||
if (!active || (setseek < 0 && !stream_playback->is_playing())) {
|
||||
active = false;
|
||||
if (!active.is_set() || (setseek.get() < 0 && !stream_playback->is_playing())) {
|
||||
active.clear();
|
||||
set_process_internal(false);
|
||||
emit_signal("finished");
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ void AudioStreamPlayer::_notification(int p_what) {
|
|||
void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
|
||||
AudioServer::get_singleton()->lock();
|
||||
|
||||
if (active && stream_playback.is_valid() && !stream_paused) {
|
||||
if (active.is_set() && stream_playback.is_valid() && !stream_paused) {
|
||||
//changing streams out of the blue is not a great idea, but at least
|
||||
//lets try to somehow avoid a click
|
||||
|
||||
|
@ -196,9 +196,9 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
|
|||
if (stream_playback.is_valid()) {
|
||||
stream_playback.unref();
|
||||
stream.unref();
|
||||
active = false;
|
||||
setseek = -1;
|
||||
setstop = false;
|
||||
active.clear();
|
||||
setseek.set(-1);
|
||||
setstop.clear();
|
||||
}
|
||||
|
||||
if (p_stream.is_valid()) {
|
||||
|
@ -237,29 +237,29 @@ float AudioStreamPlayer::get_pitch_scale() const {
|
|||
void AudioStreamPlayer::play(float p_from_pos) {
|
||||
if (stream_playback.is_valid()) {
|
||||
//mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
|
||||
setseek = p_from_pos;
|
||||
stop_has_priority = false;
|
||||
active = true;
|
||||
setseek.set(p_from_pos);
|
||||
stop_has_priority.clear();
|
||||
active.set();
|
||||
set_process_internal(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer::seek(float p_seconds) {
|
||||
if (stream_playback.is_valid()) {
|
||||
setseek = p_seconds;
|
||||
setseek.set(p_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlayer::stop() {
|
||||
if (stream_playback.is_valid() && active) {
|
||||
setstop = true;
|
||||
stop_has_priority = true;
|
||||
if (stream_playback.is_valid() && active.is_set()) {
|
||||
setstop.set();
|
||||
stop_has_priority.set();
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioStreamPlayer::is_playing() const {
|
||||
if (stream_playback.is_valid()) {
|
||||
return active && !setstop; //&& stream_playback->is_playing();
|
||||
return active.is_set() && !setstop.is_set(); //&& stream_playback->is_playing();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -267,8 +267,9 @@ bool AudioStreamPlayer::is_playing() const {
|
|||
|
||||
float AudioStreamPlayer::get_playback_position() {
|
||||
if (stream_playback.is_valid()) {
|
||||
if (setseek >= 0.0) {
|
||||
return setseek;
|
||||
float ss = setseek.get();
|
||||
if (ss >= 0.0) {
|
||||
return ss;
|
||||
}
|
||||
return stream_playback->get_playback_position();
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ void AudioStreamPlayer::_set_playing(bool p_enable) {
|
|||
}
|
||||
|
||||
bool AudioStreamPlayer::_is_active() const {
|
||||
return active;
|
||||
return active.is_set();
|
||||
}
|
||||
|
||||
void AudioStreamPlayer::set_stream_paused(bool p_pause) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef AUDIO_STREAM_PLAYER_H
|
||||
#define AUDIO_STREAM_PLAYER_H
|
||||
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
|
||||
|
@ -49,12 +50,12 @@ private:
|
|||
Ref<AudioStream> stream;
|
||||
Vector<AudioFrame> mix_buffer;
|
||||
Vector<AudioFrame> fadeout_buffer;
|
||||
bool use_fadeout = false;
|
||||
bool use_fadeout;
|
||||
|
||||
volatile float setseek = -1.0;
|
||||
volatile bool active = false;
|
||||
volatile bool setstop = false;
|
||||
volatile bool stop_has_priority = false;
|
||||
SafeNumeric<float> setseek{ -1.0 };
|
||||
SafeFlag active;
|
||||
SafeFlag setstop;
|
||||
SafeFlag stop_has_priority;
|
||||
|
||||
float mix_volume_db = 0.0;
|
||||
float pitch_scale = 1.0;
|
||||
|
|
|
@ -49,7 +49,7 @@ Error HTTPRequest::_parse_url(const String &p_url) {
|
|||
got_response = false;
|
||||
body_len = -1;
|
||||
body.resize(0);
|
||||
downloaded = 0;
|
||||
downloaded.set(0);
|
||||
redirections = 0;
|
||||
|
||||
String url_lower = url.to_lower();
|
||||
|
@ -159,9 +159,9 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
|
|||
|
||||
requesting = true;
|
||||
|
||||
if (use_threads) {
|
||||
thread_done = false;
|
||||
thread_request_quit = false;
|
||||
if (use_threads.is_set()) {
|
||||
thread_done.clear();
|
||||
thread_request_quit.clear();
|
||||
client->set_blocking_mode(true);
|
||||
thread.start(_thread_func, this);
|
||||
} else {
|
||||
|
@ -186,7 +186,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
|
|||
if (err != OK) {
|
||||
hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
|
||||
} else {
|
||||
while (!hr->thread_request_quit) {
|
||||
while (!hr->thread_request_quit.is_set()) {
|
||||
bool exit = hr->_update_connection();
|
||||
if (exit) {
|
||||
break;
|
||||
|
@ -195,7 +195,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
|
|||
}
|
||||
}
|
||||
|
||||
hr->thread_done = true;
|
||||
hr->thread_done.set();
|
||||
}
|
||||
|
||||
void HTTPRequest::cancel_request() {
|
||||
|
@ -205,10 +205,10 @@ void HTTPRequest::cancel_request() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!use_threads) {
|
||||
if (!use_threads.is_set()) {
|
||||
set_process_internal(false);
|
||||
} else {
|
||||
thread_request_quit = true;
|
||||
thread_request_quit.set();
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
|
|||
List<String> rheaders;
|
||||
client->get_response_headers(&rheaders);
|
||||
response_headers.resize(0);
|
||||
downloaded = 0;
|
||||
downloaded.set(0);
|
||||
for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
|
||||
response_headers.push_back(E->get());
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
|
|||
got_response = false;
|
||||
body_len = -1;
|
||||
body.resize(0);
|
||||
downloaded = 0;
|
||||
downloaded.set(0);
|
||||
redirections = new_redirs;
|
||||
*ret_value = false;
|
||||
return true;
|
||||
|
@ -389,7 +389,7 @@ bool HTTPRequest::_update_connection() {
|
|||
client->poll();
|
||||
|
||||
PackedByteArray chunk = client->read_response_body_chunk();
|
||||
downloaded += chunk.size();
|
||||
downloaded.add(chunk.size());
|
||||
|
||||
if (file) {
|
||||
const uint8_t *r = chunk.ptr();
|
||||
|
@ -402,13 +402,13 @@ bool HTTPRequest::_update_connection() {
|
|||
body.append_array(chunk);
|
||||
}
|
||||
|
||||
if (body_size_limit >= 0 && downloaded > body_size_limit) {
|
||||
if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
|
||||
call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (body_len >= 0) {
|
||||
if (downloaded == body_len) {
|
||||
if (downloaded.get() == body_len) {
|
||||
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
|
||||
return true;
|
||||
}
|
||||
|
@ -478,7 +478,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
|
|||
|
||||
void HTTPRequest::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||
if (use_threads) {
|
||||
if (use_threads.is_set()) {
|
||||
return;
|
||||
}
|
||||
bool done = _update_connection();
|
||||
|
@ -497,11 +497,11 @@ void HTTPRequest::_notification(int p_what) {
|
|||
|
||||
void HTTPRequest::set_use_threads(bool p_use) {
|
||||
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
|
||||
use_threads = p_use;
|
||||
use_threads.set_to(p_use);
|
||||
}
|
||||
|
||||
bool HTTPRequest::is_using_threads() const {
|
||||
return use_threads;
|
||||
return use_threads.is_set();
|
||||
}
|
||||
|
||||
void HTTPRequest::set_accept_gzip(bool p_gzip) {
|
||||
|
@ -555,7 +555,7 @@ int HTTPRequest::get_max_redirects() const {
|
|||
}
|
||||
|
||||
int HTTPRequest::get_downloaded_bytes() const {
|
||||
return downloaded;
|
||||
return downloaded.get();
|
||||
}
|
||||
|
||||
int HTTPRequest::get_body_size() const {
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/io/http_client.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "node.h"
|
||||
#include "scene/main/timer.h"
|
||||
|
||||
|
@ -74,7 +75,7 @@ private:
|
|||
bool request_sent = false;
|
||||
Ref<HTTPClient> client;
|
||||
PackedByteArray body;
|
||||
volatile bool use_threads = false;
|
||||
SafeFlag use_threads;
|
||||
bool accept_gzip = true;
|
||||
|
||||
bool got_response = false;
|
||||
|
@ -86,7 +87,7 @@ private:
|
|||
FileAccess *file = nullptr;
|
||||
|
||||
int body_len = -1;
|
||||
volatile int downloaded = 0;
|
||||
SafeNumeric<int> downloaded;
|
||||
int body_size_limit = -1;
|
||||
|
||||
int redirections = 0;
|
||||
|
@ -107,8 +108,8 @@ private:
|
|||
bool has_header(const PackedStringArray &p_headers, const String &p_header_name);
|
||||
String get_header_value(const PackedStringArray &p_headers, const String &header_name);
|
||||
|
||||
volatile bool thread_done = false;
|
||||
volatile bool thread_request_quit = false;
|
||||
SafeFlag thread_done;
|
||||
SafeFlag thread_request_quit;
|
||||
|
||||
Thread thread;
|
||||
|
||||
|
|
|
@ -1400,11 +1400,11 @@ bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const Strin
|
|||
}
|
||||
|
||||
void VisualShader::_update_shader() const {
|
||||
if (!dirty) {
|
||||
if (!dirty.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
dirty = false;
|
||||
dirty.clear();
|
||||
|
||||
StringBuilder global_code;
|
||||
StringBuilder global_code_per_node;
|
||||
|
@ -1590,11 +1590,11 @@ void VisualShader::_update_shader() const {
|
|||
}
|
||||
|
||||
void VisualShader::_queue_update() {
|
||||
if (dirty) {
|
||||
if (dirty.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
dirty.set();
|
||||
call_deferred("_update_shader");
|
||||
}
|
||||
|
||||
|
@ -1614,7 +1614,7 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) {
|
|||
}
|
||||
|
||||
void VisualShader::rebuild() {
|
||||
dirty = true;
|
||||
dirty.set();
|
||||
_update_shader();
|
||||
}
|
||||
|
||||
|
@ -1668,6 +1668,7 @@ void VisualShader::_bind_methods() {
|
|||
}
|
||||
|
||||
VisualShader::VisualShader() {
|
||||
dirty.set();
|
||||
for (int i = 0; i < TYPE_MAX; i++) {
|
||||
Ref<VisualShaderNodeOutput> output;
|
||||
output.instance();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define VISUAL_SHADER_H
|
||||
|
||||
#include "core/string/string_builder.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/resources/shader.h"
|
||||
|
||||
|
@ -99,7 +100,7 @@ private:
|
|||
|
||||
static RenderModeEnums render_mode_enums[];
|
||||
|
||||
volatile mutable bool dirty = true;
|
||||
mutable SafeFlag dirty;
|
||||
void _queue_update();
|
||||
|
||||
union ConnectionKey {
|
||||
|
|
|
@ -131,7 +131,7 @@ bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) {
|
|||
src_read = read_space;
|
||||
}
|
||||
|
||||
rb_read_pos = (rb_read_pos + src_read) & rb_mask;
|
||||
rb_read_pos.set((rb_read_pos.get() + src_read) & rb_mask);
|
||||
|
||||
// Create fadeout effect for the end of stream (note that it can be because of slow writer)
|
||||
if (p_frames - target_todo > 0) {
|
||||
|
@ -183,8 +183,8 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m
|
|||
src_mix_rate = p_src_mix_rate;
|
||||
target_mix_rate = p_target_mix_rate;
|
||||
offset = 0;
|
||||
rb_read_pos = 0;
|
||||
rb_write_pos = 0;
|
||||
rb_read_pos.set(0);
|
||||
rb_write_pos.set(0);
|
||||
|
||||
//avoid maybe strange noises upon load
|
||||
for (unsigned int i = 0; i < (rb_len * channels); i++) {
|
||||
|
@ -205,8 +205,8 @@ void AudioRBResampler::clear() {
|
|||
memdelete_arr(read_buf);
|
||||
rb = nullptr;
|
||||
offset = 0;
|
||||
rb_read_pos = 0;
|
||||
rb_write_pos = 0;
|
||||
rb_read_pos.set(0);
|
||||
rb_write_pos.set(0);
|
||||
read_buf = nullptr;
|
||||
}
|
||||
|
||||
|
@ -214,8 +214,8 @@ AudioRBResampler::AudioRBResampler() {
|
|||
rb = nullptr;
|
||||
offset = 0;
|
||||
read_buf = nullptr;
|
||||
rb_read_pos = 0;
|
||||
rb_write_pos = 0;
|
||||
rb_read_pos.set(0);
|
||||
rb_write_pos.set(0);
|
||||
|
||||
rb_bits = 0;
|
||||
rb_len = 0;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define AUDIO_RB_RESAMPLER_H
|
||||
|
||||
#include "core/os/memory.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "servers/audio_server.h"
|
||||
|
||||
|
@ -44,8 +45,8 @@ struct AudioRBResampler {
|
|||
uint32_t src_mix_rate;
|
||||
uint32_t target_mix_rate;
|
||||
|
||||
volatile int rb_read_pos;
|
||||
volatile int rb_write_pos;
|
||||
SafeNumeric<int> rb_read_pos;
|
||||
SafeNumeric<int> rb_write_pos;
|
||||
|
||||
int32_t offset; //contains the fractional remainder of the resampler
|
||||
enum {
|
||||
|
@ -62,8 +63,8 @@ struct AudioRBResampler {
|
|||
|
||||
public:
|
||||
_FORCE_INLINE_ void flush() {
|
||||
rb_read_pos = 0;
|
||||
rb_write_pos = 0;
|
||||
rb_read_pos.set(0);
|
||||
rb_write_pos.set(0);
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
|
@ -78,8 +79,8 @@ public:
|
|||
_FORCE_INLINE_ int get_writer_space() const {
|
||||
int space, r, w;
|
||||
|
||||
r = rb_read_pos;
|
||||
w = rb_write_pos;
|
||||
r = rb_read_pos.get();
|
||||
w = rb_write_pos.get();
|
||||
|
||||
if (r == w) {
|
||||
space = rb_len - 1;
|
||||
|
@ -95,8 +96,8 @@ public:
|
|||
_FORCE_INLINE_ int get_reader_space() const {
|
||||
int space, r, w;
|
||||
|
||||
r = rb_read_pos;
|
||||
w = rb_write_pos;
|
||||
r = rb_read_pos.get();
|
||||
w = rb_write_pos.get();
|
||||
|
||||
if (r == w) {
|
||||
space = 0;
|
||||
|
@ -110,48 +111,52 @@ public:
|
|||
}
|
||||
|
||||
_FORCE_INLINE_ bool has_data() const {
|
||||
return rb && rb_read_pos != rb_write_pos;
|
||||
return rb && rb_read_pos.get() != rb_write_pos.get();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float *get_write_buffer() { return read_buf; }
|
||||
_FORCE_INLINE_ void write(uint32_t p_frames) {
|
||||
ERR_FAIL_COND(p_frames >= rb_len);
|
||||
|
||||
int wp = rb_write_pos.get();
|
||||
|
||||
switch (channels) {
|
||||
case 1: {
|
||||
for (uint32_t i = 0; i < p_frames; i++) {
|
||||
rb[rb_write_pos] = read_buf[i];
|
||||
rb_write_pos = (rb_write_pos + 1) & rb_mask;
|
||||
rb[wp] = read_buf[i];
|
||||
wp = (wp + 1) & rb_mask;
|
||||
}
|
||||
} break;
|
||||
case 2: {
|
||||
for (uint32_t i = 0; i < p_frames; i++) {
|
||||
rb[(rb_write_pos << 1) + 0] = read_buf[(i << 1) + 0];
|
||||
rb[(rb_write_pos << 1) + 1] = read_buf[(i << 1) + 1];
|
||||
rb_write_pos = (rb_write_pos + 1) & rb_mask;
|
||||
rb[(wp << 1) + 0] = read_buf[(i << 1) + 0];
|
||||
rb[(wp << 1) + 1] = read_buf[(i << 1) + 1];
|
||||
wp = (wp + 1) & rb_mask;
|
||||
}
|
||||
} break;
|
||||
case 4: {
|
||||
for (uint32_t i = 0; i < p_frames; i++) {
|
||||
rb[(rb_write_pos << 2) + 0] = read_buf[(i << 2) + 0];
|
||||
rb[(rb_write_pos << 2) + 1] = read_buf[(i << 2) + 1];
|
||||
rb[(rb_write_pos << 2) + 2] = read_buf[(i << 2) + 2];
|
||||
rb[(rb_write_pos << 2) + 3] = read_buf[(i << 2) + 3];
|
||||
rb_write_pos = (rb_write_pos + 1) & rb_mask;
|
||||
rb[(wp << 2) + 0] = read_buf[(i << 2) + 0];
|
||||
rb[(wp << 2) + 1] = read_buf[(i << 2) + 1];
|
||||
rb[(wp << 2) + 2] = read_buf[(i << 2) + 2];
|
||||
rb[(wp << 2) + 3] = read_buf[(i << 2) + 3];
|
||||
wp = (wp + 1) & rb_mask;
|
||||
}
|
||||
} break;
|
||||
case 6: {
|
||||
for (uint32_t i = 0; i < p_frames; i++) {
|
||||
rb[(rb_write_pos * 6) + 0] = read_buf[(i * 6) + 0];
|
||||
rb[(rb_write_pos * 6) + 1] = read_buf[(i * 6) + 1];
|
||||
rb[(rb_write_pos * 6) + 2] = read_buf[(i * 6) + 2];
|
||||
rb[(rb_write_pos * 6) + 3] = read_buf[(i * 6) + 3];
|
||||
rb[(rb_write_pos * 6) + 4] = read_buf[(i * 6) + 4];
|
||||
rb[(rb_write_pos * 6) + 5] = read_buf[(i * 6) + 5];
|
||||
rb_write_pos = (rb_write_pos + 1) & rb_mask;
|
||||
rb[(wp * 6) + 0] = read_buf[(i * 6) + 0];
|
||||
rb[(wp * 6) + 1] = read_buf[(i * 6) + 1];
|
||||
rb[(wp * 6) + 2] = read_buf[(i * 6) + 2];
|
||||
rb[(wp * 6) + 3] = read_buf[(i * 6) + 3];
|
||||
rb[(wp * 6) + 4] = read_buf[(i * 6) + 4];
|
||||
rb[(wp * 6) + 5] = read_buf[(i * 6) + 5];
|
||||
wp = (wp + 1) & rb_mask;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
rb_write_pos.set(wp);
|
||||
}
|
||||
|
||||
int get_channel_count() const;
|
||||
|
|
|
@ -106,7 +106,7 @@ int AudioEffectCapture::get_frames_available() const {
|
|||
}
|
||||
|
||||
int64_t AudioEffectCapture::get_discarded_frames() const {
|
||||
return discarded_frames;
|
||||
return discarded_frames.get();
|
||||
}
|
||||
|
||||
int AudioEffectCapture::get_buffer_length_frames() const {
|
||||
|
@ -115,7 +115,7 @@ int AudioEffectCapture::get_buffer_length_frames() const {
|
|||
}
|
||||
|
||||
int64_t AudioEffectCapture::get_pushed_frames() const {
|
||||
return pushed_frames;
|
||||
return pushed_frames.get();
|
||||
}
|
||||
|
||||
void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
|
||||
|
@ -129,9 +129,9 @@ void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFr
|
|||
// Add incoming audio frames to the IO ring buffer
|
||||
int32_t ret = buffer.write(p_src_frames, p_frame_count);
|
||||
ERR_FAIL_COND_MSG(ret != p_frame_count, "Failed to add data to effect capture ring buffer despite sufficient space.");
|
||||
atomic_add(&base->pushed_frames, p_frame_count);
|
||||
base->pushed_frames.add(p_frame_count);
|
||||
} else {
|
||||
atomic_add(&base->discarded_frames, p_frame_count);
|
||||
base->discarded_frames.add(p_frame_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ class AudioEffectCapture : public AudioEffect {
|
|||
friend class AudioEffectCaptureInstance;
|
||||
|
||||
RingBuffer<AudioFrame> buffer;
|
||||
uint64_t discarded_frames = 0;
|
||||
uint64_t pushed_frames = 0;
|
||||
SafeNumeric<uint64_t> discarded_frames;
|
||||
SafeNumeric<uint64_t> pushed_frames;
|
||||
float buffer_length_seconds = 0.1f;
|
||||
bool buffer_initialized = false;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "core/os/os.h"
|
||||
|
||||
void PhysicsServer2DWrapMT::thread_exit() {
|
||||
exit = true;
|
||||
exit.set();
|
||||
}
|
||||
|
||||
void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
|
||||
|
@ -52,9 +52,9 @@ void PhysicsServer2DWrapMT::thread_loop() {
|
|||
|
||||
physics_2d_server->init();
|
||||
|
||||
exit = false;
|
||||
step_thread_up = true;
|
||||
while (!exit) {
|
||||
exit.clear();
|
||||
step_thread_up.set();
|
||||
while (!exit.is_set()) {
|
||||
// flush commands one by one, until exit is requested
|
||||
command_queue.wait_and_flush_one();
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ void PhysicsServer2DWrapMT::init() {
|
|||
if (create_thread) {
|
||||
//OS::get_singleton()->release_rendering_thread();
|
||||
thread.start(_thread_callback, this);
|
||||
while (!step_thread_up) {
|
||||
while (!step_thread_up.is_set()) {
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
} else {
|
||||
|
@ -120,7 +120,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool
|
|||
physics_2d_server = p_contained;
|
||||
create_thread = p_create_thread;
|
||||
step_pending = 0;
|
||||
step_thread_up = false;
|
||||
|
||||
pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc");
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/config/project_settings.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/templates/command_queue_mt.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "servers/physics_server_2d.h"
|
||||
|
||||
#ifdef DEBUG_SYNC
|
||||
|
@ -52,9 +53,9 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D {
|
|||
|
||||
Thread::ID server_thread;
|
||||
Thread::ID main_thread;
|
||||
volatile bool exit;
|
||||
SafeFlag exit;
|
||||
Thread thread;
|
||||
volatile bool step_thread_up;
|
||||
SafeFlag step_thread_up;
|
||||
bool create_thread;
|
||||
|
||||
Semaphore step_sem;
|
||||
|
|
|
@ -237,7 +237,7 @@ void RenderingServerDefault::init() {
|
|||
thread.start(_thread_callback, this);
|
||||
print_verbose("RenderingServerWrapMT: Starting render thread");
|
||||
}
|
||||
while (!draw_thread_up) {
|
||||
while (!draw_thread_up.is_set()) {
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
print_verbose("RenderingServerWrapMT: Finished render thread");
|
||||
|
@ -329,17 +329,17 @@ bool RenderingServerDefault::is_low_end() const {
|
|||
}
|
||||
|
||||
void RenderingServerDefault::_thread_exit() {
|
||||
exit = true;
|
||||
exit.set();
|
||||
}
|
||||
|
||||
void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) {
|
||||
if (!atomic_decrement(&draw_pending)) {
|
||||
if (!draw_pending.decrement()) {
|
||||
_draw(p_swap_buffers, frame_step);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerDefault::_thread_flush() {
|
||||
atomic_decrement(&draw_pending);
|
||||
draw_pending.decrement();
|
||||
}
|
||||
|
||||
void RenderingServerDefault::_thread_callback(void *_instance) {
|
||||
|
@ -355,9 +355,8 @@ void RenderingServerDefault::_thread_loop() {
|
|||
|
||||
_init();
|
||||
|
||||
exit = false;
|
||||
draw_thread_up = true;
|
||||
while (!exit) {
|
||||
draw_thread_up.set();
|
||||
while (!exit.is_set()) {
|
||||
// flush commands one by one, until exit is requested
|
||||
command_queue.wait_and_flush_one();
|
||||
}
|
||||
|
@ -371,7 +370,7 @@ void RenderingServerDefault::_thread_loop() {
|
|||
|
||||
void RenderingServerDefault::sync() {
|
||||
if (create_thread) {
|
||||
atomic_increment(&draw_pending);
|
||||
draw_pending.increment();
|
||||
command_queue.push_and_sync(this, &RenderingServerDefault::_thread_flush);
|
||||
} else {
|
||||
command_queue.flush_all(); //flush all pending from other threads
|
||||
|
@ -380,7 +379,7 @@ void RenderingServerDefault::sync() {
|
|||
|
||||
void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
|
||||
if (create_thread) {
|
||||
atomic_increment(&draw_pending);
|
||||
draw_pending.increment();
|
||||
command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step);
|
||||
} else {
|
||||
_draw(p_swap_buffers, frame_step);
|
||||
|
@ -390,8 +389,6 @@ void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
|
|||
RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
|
||||
command_queue(p_create_thread) {
|
||||
create_thread = p_create_thread;
|
||||
draw_pending = 0;
|
||||
draw_thread_up = false;
|
||||
|
||||
if (!p_create_thread) {
|
||||
server_thread = Thread::get_caller_id();
|
||||
|
|
|
@ -89,12 +89,12 @@ class RenderingServerDefault : public RenderingServer {
|
|||
void _thread_loop();
|
||||
|
||||
Thread::ID server_thread;
|
||||
volatile bool exit;
|
||||
SafeFlag exit;
|
||||
Thread thread;
|
||||
volatile bool draw_thread_up;
|
||||
SafeFlag draw_thread_up;
|
||||
bool create_thread;
|
||||
|
||||
uint64_t draw_pending;
|
||||
SafeNumeric<uint64_t> draw_pending;
|
||||
void _thread_draw(bool p_swap_buffers, double frame_step);
|
||||
void _thread_flush();
|
||||
|
||||
|
|
Loading…
Reference in a new issue