atomic.hpp: replace std::atomic with atomic_t

Dual dependency is nothing good.
This commit is contained in:
Nekotekina 2020-12-06 15:15:19 +03:00
parent b16cc618b5
commit eb66302907
35 changed files with 42 additions and 82 deletions

View File

@ -5,7 +5,6 @@
#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_event.h" #include "Emu/Cell/lv2/sys_event.h"
#include "cellAudio.h" #include "cellAudio.h"
#include <atomic>
#include <cmath> #include <cmath>
LOG_CHANNEL(cellAudio); LOG_CHANNEL(cellAudio);

View File

@ -11,7 +11,6 @@
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
#include <thread> #include <thread>
#include <atomic>
LOG_CHANNEL(cellGcmSys); LOG_CHANNEL(cellGcmSys);

View File

@ -15,8 +15,6 @@
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
#include "cellSpurs.h" #include "cellSpurs.h"
#include <atomic>
LOG_CHANNEL(cellSpurs); LOG_CHANNEL(cellSpurs);
template <> template <>

View File

@ -4,8 +4,6 @@
#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_process.h"
#include "cellSync.h" #include "cellSync.h"
#include <atomic>
LOG_CHANNEL(cellSync); LOG_CHANNEL(cellSync);
template<> template<>

View File

@ -4,8 +4,6 @@
#include "Utilities/BEType.h" #include "Utilities/BEType.h"
#include <atomic>
error_code sceNpInit(u32 poolsize, vm::ptr<void> poolptr); error_code sceNpInit(u32 poolsize, vm::ptr<void> poolptr);
error_code sceNpTerm(); error_code sceNpTerm();

View File

@ -4,8 +4,6 @@
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include <atomic>
// Error codes // Error codes
enum SceNpMatching2Error : u32 enum SceNpMatching2Error : u32
{ {

View File

@ -4,8 +4,6 @@
#include "Utilities/BEType.h" #include "Utilities/BEType.h"
#include <atomic>
// Return codes // Return codes
enum SceNpClansError : u32 enum SceNpClansError : u32
{ {
@ -261,5 +259,5 @@ struct SceNpClansBlacklistEntry
struct sce_np_clans_manager struct sce_np_clans_manager
{ {
std::atomic<bool> is_initialized = false; atomic_t<bool> is_initialized = false;
}; };

View File

@ -2,8 +2,6 @@
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include <atomic>
// Return codes // Return codes
enum sceNpSnsError : u32 enum sceNpSnsError : u32
{ {
@ -81,5 +79,5 @@ struct SceNpSnsFbLongAccessTokenResult
struct sce_np_sns_manager struct sce_np_sns_manager
{ {
std::atomic<bool> is_initialized = false; atomic_t<bool> is_initialized = false;
}; };

View File

@ -50,7 +50,7 @@ struct trophy_handle_t
struct sce_np_trophy_manager struct sce_np_trophy_manager
{ {
shared_mutex mtx; shared_mutex mtx;
std::atomic<bool> is_initialized = false; atomic_t<bool> is_initialized = false;
// Get context + check handle given // Get context + check handle given
static std::pair<trophy_context_t*, SceNpTrophyError> get_context_ex(u32 context, u32 handle) static std::pair<trophy_context_t*, SceNpTrophyError> get_context_ex(u32 context, u32 handle)

View File

@ -2,7 +2,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include <atomic>
// Error codes // Error codes
enum SceNpTrophyError : u32 enum SceNpTrophyError : u32

View File

@ -5,7 +5,6 @@
#include "cellRtc.h" #include "cellRtc.h"
#include "sceNp.h" #include "sceNp.h"
#include <atomic>
#include <map> #include <map>
// Constants for TUS functions and structures // Constants for TUS functions and structures
@ -136,7 +135,7 @@ private:
public: public:
std::mutex mtx; std::mutex mtx;
std::atomic<bool> is_initialized = false; atomic_t<bool> is_initialized = false;
s32 add_title_context(); s32 add_title_context();
bool check_title_context_id(s32 titleCtxId); bool check_title_context_id(s32 titleCtxId);

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include <atomic>
enum enum
{ {
SCE_NP_UTIL_BANDWIDTH_TEST_STATUS_NONE = 0, SCE_NP_UTIL_BANDWIDTH_TEST_STATUS_NONE = 0,
@ -20,5 +18,5 @@ struct SceNpUtilBandwidthTestResult
struct sce_np_util_manager struct sce_np_util_manager
{ {
std::atomic<bool> is_initialized = false; atomic_t<bool> is_initialized = false;
}; };

View File

@ -6,8 +6,6 @@
#include "Emu/Cell/lv2/sys_mutex.h" #include "Emu/Cell/lv2/sys_mutex.h"
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
#include <atomic>
LOG_CHANNEL(sysPrxForUser); LOG_CHANNEL(sysPrxForUser);
error_code sys_lwmutex_create(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr) error_code sys_lwmutex_create(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)

View File

@ -7,7 +7,6 @@
#include "Utilities/sysinfo.h" #include "Utilities/sysinfo.h"
#include "Emu/Cell/Common.h" #include "Emu/Cell/Common.h"
#include <atomic>
#include <bit> #include <bit>
#include <cmath> #include <cmath>

View File

@ -4,8 +4,6 @@
#include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/RawSPUThread.h"
#include <atomic>
inline void try_start(spu_thread& spu) inline void try_start(spu_thread& spu)
{ {
reader_lock lock(spu.run_ctrl_mtx); reader_lock lock(spu.run_ctrl_mtx);

View File

@ -27,7 +27,6 @@
#include <cmath> #include <cmath>
#include <cfenv> #include <cfenv>
#include <atomic>
#include <thread> #include <thread>
#include <shared_mutex> #include <shared_mutex>
#include "util/vm.hpp" #include "util/vm.hpp"
@ -298,14 +297,14 @@ namespace spu
{ {
namespace scheduler namespace scheduler
{ {
std::array<std::atomic<u8>, 65536> atomic_instruction_table = {}; std::array<atomic_t<u8>, 65536> atomic_instruction_table = {};
constexpr u32 native_jiffy_duration_us = 1500; //About 1ms resolution with a half offset constexpr u32 native_jiffy_duration_us = 1500; //About 1ms resolution with a half offset
void acquire_pc_address(spu_thread& spu, u32 pc, u32 timeout_ms, u32 max_concurrent_instructions) void acquire_pc_address(spu_thread& spu, u32 pc, u32 timeout_ms, u32 max_concurrent_instructions)
{ {
const u32 pc_offset = pc >> 2; const u32 pc_offset = pc >> 2;
if (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions) if (atomic_instruction_table[pc_offset].observe() >= max_concurrent_instructions)
{ {
spu.state += cpu_flag::wait + cpu_flag::temp; spu.state += cpu_flag::wait + cpu_flag::temp;
@ -315,7 +314,7 @@ namespace spu
const u64 start = get_system_time(); const u64 start = get_system_time();
auto remaining = timeout; auto remaining = timeout;
while (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions) while (atomic_instruction_table[pc_offset].observe() >= max_concurrent_instructions)
{ {
if (remaining >= native_jiffy_duration_us) if (remaining >= native_jiffy_duration_us)
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(1ms);
@ -332,7 +331,7 @@ namespace spu
else else
{ {
//Slight pause if function is overburdened //Slight pause if function is overburdened
const auto count = atomic_instruction_table[pc_offset].load(std::memory_order_consume) * 100ull; const auto count = atomic_instruction_table[pc_offset].observe() * 100ull;
busy_wait(count); busy_wait(count);
} }

View File

@ -7,7 +7,7 @@
namespace input namespace input
{ {
std::atomic<bool> g_intercepted{false}; atomic_t<bool> g_intercepted{false};
void SetIntercepted(bool intercepted) void SetIntercepted(bool intercepted)
{ {

View File

@ -1,10 +1,8 @@
#pragma once #pragma once
#include <atomic>
namespace input namespace input
{ {
extern std::atomic<bool> g_intercepted; extern atomic_t<bool> g_intercepted;
void SetIntercepted(bool intercepted); void SetIntercepted(bool intercepted);
} }

View File

@ -7,7 +7,6 @@
#include "Emu/RSX/RSXThread.h" #include "Emu/RSX/RSXThread.h"
#include <map> #include <map>
#include <atomic>
namespace rsx namespace rsx
{ {

View File

@ -3,8 +3,6 @@
#include "texture_cache_predictor.h" #include "texture_cache_predictor.h"
#include "texture_cache_helpers.h" #include "texture_cache_helpers.h"
#include <atomic>
extern u64 get_system_time(); extern u64 get_system_time();
#define RSX_GCM_FORMAT_IGNORED 0 #define RSX_GCM_FORMAT_IGNORED 0
@ -279,7 +277,7 @@ namespace rsx
std::vector<image_view_type> m_uncached_subresources; std::vector<image_view_type> m_uncached_subresources;
predictor_type m_predictor; predictor_type m_predictor;
std::atomic<u64> m_cache_update_tag = {0}; atomic_t<u64> m_cache_update_tag = {0};
address_range read_only_range; address_range read_only_range;
address_range no_access_range; address_range no_access_range;
@ -298,10 +296,10 @@ namespace rsx
const u32 m_max_zombie_objects = 64; //Limit on how many texture objects to keep around for reuse after they are invalidated const u32 m_max_zombie_objects = 64; //Limit on how many texture objects to keep around for reuse after they are invalidated
//Other statistics //Other statistics
std::atomic<u32> m_flushes_this_frame = { 0 }; atomic_t<u32> m_flushes_this_frame = { 0 };
std::atomic<u32> m_misses_this_frame = { 0 }; atomic_t<u32> m_misses_this_frame = { 0 };
std::atomic<u32> m_speculations_this_frame = { 0 }; atomic_t<u32> m_speculations_this_frame = { 0 };
std::atomic<u32> m_unavoidable_hard_faults_this_frame = { 0 }; atomic_t<u32> m_unavoidable_hard_faults_this_frame = { 0 };
static const u32 m_predict_max_flushes_per_frame = 50; // Above this number the predictions are disabled static const u32 m_predict_max_flushes_per_frame = 50; // Above this number the predictions are disabled
// Invalidation // Invalidation
@ -621,7 +619,7 @@ namespace rsx
} }
// Return a set containing all sections that should be flushed/unprotected/reprotected // Return a set containing all sections that should be flushed/unprotected/reprotected
std::atomic<u64> m_last_section_cache_tag = 0; atomic_t<u64> m_last_section_cache_tag = 0;
intersecting_set get_intersecting_set(const address_range &fault_range) intersecting_set get_intersecting_set(const address_range &fault_range)
{ {
AUDIT(fault_range.is_page_range()); AUDIT(fault_range.is_page_range());
@ -876,7 +874,7 @@ namespace rsx
{ {
// There is something to flush, but we've been asked to defer it // There is something to flush, but we've been asked to defer it
result.num_flushable = static_cast<int>(result.sections_to_flush.size()); result.num_flushable = static_cast<int>(result.sections_to_flush.size());
result.cache_tag = m_cache_update_tag.load(std::memory_order_consume); result.cache_tag = m_cache_update_tag.load();
return result; return result;
} }
else if (has_flushables || has_unprotectables) else if (has_flushables || has_unprotectables)
@ -1275,7 +1273,7 @@ namespace rsx
AUDIT(data.cause.deferred_flush()); AUDIT(data.cause.deferred_flush());
AUDIT(!data.flushed); AUDIT(!data.flushed);
if (m_cache_update_tag.load(std::memory_order_consume) == data.cache_tag) if (m_cache_update_tag.load() == data.cache_tag)
{ {
//1. Write memory to cpu side //1. Write memory to cpu side
flush_set(cmd, data, std::forward<Args>(extras)...); flush_set(cmd, data, std::forward<Args>(extras)...);
@ -2836,7 +2834,7 @@ namespace rsx
{ {
if (!m_flush_always_cache.empty()) if (!m_flush_always_cache.empty())
{ {
if (m_cache_update_tag.load(std::memory_order_consume) != m_flush_always_update_timestamp) if (m_cache_update_tag.load() != m_flush_always_update_timestamp)
{ {
std::lock_guard lock(m_cache_mutex); std::lock_guard lock(m_cache_mutex);
bool update_tag = false; bool update_tag = false;
@ -2856,7 +2854,7 @@ namespace rsx
} }
if (update_tag) update_cache_tag(); if (update_tag) update_cache_tag();
m_flush_always_update_timestamp = m_cache_update_tag.load(std::memory_order_consume); m_flush_always_update_timestamp = m_cache_update_tag.load();
#ifdef TEXTURE_CACHE_DEBUG #ifdef TEXTURE_CACHE_DEBUG
// Check that the cache has the correct protections // Check that the cache has the correct protections

View File

@ -3,8 +3,6 @@
#include "../rsx_cache.h" #include "../rsx_cache.h"
#include "../rsx_utils.h" #include "../rsx_utils.h"
#include "TextureUtils.h" #include "TextureUtils.h"
#include <atomic>
namespace rsx namespace rsx
{ {
@ -339,7 +337,7 @@ namespace rsx
public: public:
// Per-frame statistics // Per-frame statistics
std::atomic<u32> m_mispredictions_this_frame = {0}; atomic_t<u32> m_mispredictions_this_frame = {0};
// Constructors // Constructors
texture_cache_predictor(texture_cache_type* tex_cache) texture_cache_predictor(texture_cache_type* tex_cache)

View File

@ -6,8 +6,6 @@
#include <list> #include <list>
#include <unordered_set> #include <unordered_set>
#include <atomic>
namespace rsx namespace rsx
{ {
@ -324,9 +322,9 @@ namespace rsx
address_range range = {}; address_range range = {};
block_container_type sections = {}; block_container_type sections = {};
unowned_container_type unowned; // pointers to sections from other blocks that overlap this block unowned_container_type unowned; // pointers to sections from other blocks that overlap this block
std::atomic<u32> exists_count = 0; atomic_t<u32> exists_count = 0;
std::atomic<u32> locked_count = 0; atomic_t<u32> locked_count = 0;
std::atomic<u32> unreleased_count = 0; atomic_t<u32> unreleased_count = 0;
ranged_storage_type *m_storage = nullptr; ranged_storage_type *m_storage = nullptr;
inline void add_owned_section_overlaps(section_storage_type &section) inline void add_owned_section_overlaps(section_storage_type &section)
@ -567,8 +565,8 @@ namespace rsx
bool m_purging = false; bool m_purging = false;
public: public:
std::atomic<u32> m_unreleased_texture_objects = { 0 }; //Number of invalidated objects not yet freed from memory atomic_t<u32> m_unreleased_texture_objects = { 0 }; //Number of invalidated objects not yet freed from memory
std::atomic<u64> m_texture_memory_in_use = { 0 }; atomic_t<u64> m_texture_memory_in_use = { 0 };
// Constructor // Constructor
ranged_storage(texture_cache_type *tex_cache) : ranged_storage(texture_cache_type *tex_cache) :

View File

@ -133,7 +133,7 @@ private:
shared_mutex m_sampler_mutex; shared_mutex m_sampler_mutex;
u64 surface_store_tag = 0; u64 surface_store_tag = 0;
std::atomic_bool m_samplers_dirty = {true}; atomic_t<bool> m_samplers_dirty = {true};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {}; std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {}; std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};
std::unordered_map<GLenum, std::unique_ptr<gl::texture>> m_null_textures; std::unordered_map<GLenum, std::unique_ptr<gl::texture>> m_null_textures;

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <atomic>
#include "display.h" #include "display.h"
@ -27,6 +26,6 @@ public:
virtual display_handle_t handle() const = 0; virtual display_handle_t handle() const = 0;
std::atomic<bool> screenshot_toggle = false; atomic_t<bool> screenshot_toggle = false;
virtual void take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height, bool is_bgra) = 0; virtual void take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height, bool is_bgra) = 0;
}; };

View File

@ -29,7 +29,7 @@ class GSRender;
#define CMD_DEBUG 0 #define CMD_DEBUG 0
std::atomic<bool> g_user_asked_for_frame_capture = false; atomic_t<bool> g_user_asked_for_frame_capture = false;
rsx::frame_trace_data frame_debug; rsx::frame_trace_data frame_debug;
rsx::frame_capture_data frame_capture; rsx::frame_capture_data frame_capture;

View File

@ -4,7 +4,6 @@
#include <deque> #include <deque>
#include <variant> #include <variant>
#include <stack> #include <stack>
#include <atomic>
#include "GCM.h" #include "GCM.h"
#include "rsx_cache.h" #include "rsx_cache.h"
@ -29,7 +28,7 @@
extern u64 get_guest_system_time(); extern u64 get_guest_system_time();
extern u64 get_system_time(); extern u64 get_system_time();
extern std::atomic<bool> g_user_asked_for_frame_capture; extern atomic_t<bool> g_user_asked_for_frame_capture;
extern rsx::frame_trace_data frame_debug; extern rsx::frame_trace_data frame_debug;
extern rsx::frame_capture_data frame_capture; extern rsx::frame_capture_data frame_capture;

View File

@ -13,7 +13,6 @@
#include "../GCM.h" #include "../GCM.h"
#include <thread> #include <thread>
#include <atomic>
#include <optional> #include <optional>
namespace vk namespace vk
@ -59,7 +58,7 @@ namespace vk
vk::fence* submit_fence = nullptr; vk::fence* submit_fence = nullptr;
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
std::atomic_bool pending = { false }; atomic_t<bool> pending = { false };
u64 eid_tag = 0; u64 eid_tag = 0;
u64 reset_id = 0; u64 reset_id = 0;
shared_mutex guard_mutex; shared_mutex guard_mutex;
@ -373,7 +372,7 @@ private:
shared_mutex m_sampler_mutex; shared_mutex m_sampler_mutex;
u64 surface_store_tag = 0; u64 surface_store_tag = 0;
std::atomic_bool m_samplers_dirty = { true }; atomic_t<bool> m_samplers_dirty = { true };
std::unique_ptr<vk::sampler> m_stencil_mirror_sampler; std::unique_ptr<vk::sampler> m_stencil_mirror_sampler;
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {}; std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {}; std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};

View File

@ -557,7 +557,7 @@ namespace vk
//Stuff that has been dereferenced goes into these //Stuff that has been dereferenced goes into these
std::list<temporary_storage> m_temporary_storage; std::list<temporary_storage> m_temporary_storage;
std::atomic<u32> m_temporary_memory_size = { 0 }; atomic_t<u32> m_temporary_memory_size = { 0 };
void clear() void clear()
{ {

View File

@ -8,7 +8,6 @@
#include "Emu/RSX/Common/BufferUtils.h" #include "Emu/RSX/Common/BufferUtils.h"
#include <thread> #include <thread>
#include <atomic>
namespace rsx namespace rsx
{ {

View File

@ -25,7 +25,6 @@
#include <QMenu> #include <QMenu>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QTimer> #include <QTimer>
#include <atomic>
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include "util/atomic.hpp"
#include <atomic>
class curl_handle; class curl_handle;
class progress_dialog; class progress_dialog;
@ -37,11 +36,11 @@ private:
curl_handle* m_curl = nullptr; curl_handle* m_curl = nullptr;
QByteArray m_curl_buf; QByteArray m_curl_buf;
std::atomic<bool> m_curl_abort = false; atomic_t<bool> m_curl_abort = false;
std::atomic<bool> m_curl_success = false; atomic_t<bool> m_curl_success = false;
double m_actual_download_size = -1.0; double m_actual_download_size = -1.0;
progress_dialog* m_progress_dialog = nullptr; progress_dialog* m_progress_dialog = nullptr;
std::atomic<bool> m_keep_progress_dialog_open = false; atomic_t<bool> m_keep_progress_dialog_open = false;
QString m_progress_dialog_title; QString m_progress_dialog_title;
}; };

View File

@ -41,7 +41,7 @@
LOG_CHANNEL(screenshot); LOG_CHANNEL(screenshot);
extern std::atomic<bool> g_user_asked_for_frame_capture; extern atomic_t<bool> g_user_asked_for_frame_capture;
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;

View File

@ -34,7 +34,7 @@ private:
u64 m_frames = 0; u64 m_frames = 0;
QString m_window_title; QString m_window_title;
std::atomic<bool> m_show_mouse = true; atomic_t<bool> m_show_mouse = true;
bool m_disable_mouse = false; bool m_disable_mouse = false;
bool m_disable_kb_hotkeys = false; bool m_disable_kb_hotkeys = false;
bool m_mouse_hide_and_lock = false; bool m_mouse_hide_and_lock = false;

View File

@ -52,7 +52,7 @@
LOG_CHANNEL(gui_log, "GUI"); LOG_CHANNEL(gui_log, "GUI");
extern std::atomic<bool> g_user_asked_for_frame_capture; extern atomic_t<bool> g_user_asked_for_frame_capture;
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }

View File

@ -8,7 +8,6 @@
#include "Emu/RSX/VK/VKHelpers.h" #include "Emu/RSX/VK/VKHelpers.h"
#endif #endif
#include <atomic>
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
@ -25,7 +24,7 @@ render_creator::render_creator(QObject *parent) : QObject(parent)
// plugged in. This whole contraption is for showing an error message in case that happens, so that user has // plugged in. This whole contraption is for showing an error message in case that happens, so that user has
// some idea about why the emulator window isn't showing up. // some idea about why the emulator window isn't showing up.
static std::atomic<bool> was_called = false; static atomic_t<bool> was_called = false;
if (was_called.exchange(true)) if (was_called.exchange(true))
fmt::throw_exception("Render_Creator cannot be created more than once" HERE); fmt::throw_exception("Render_Creator cannot be created more than once" HERE);