Update fundamental and Rack

This commit is contained in:
falkTX 2022-01-01 16:22:17 +00:00
parent 87b46a938e
commit d5d2d5befc
4 changed files with 38 additions and 80 deletions

@ -1 +1 @@
Subproject commit e7c2fe6d54531fd2fd25014dc722a18546393207 Subproject commit 6012b6e49a88d528d7c85a651e7261a1aa2cc575

@ -1 +1 @@
Subproject commit 9ad53329fff74989daf3365600f9fccc0b6f5266 Subproject commit 2dc80509d29880e8b8ca67ba5d1af4835a6b6cad

View file

@ -33,7 +33,6 @@
#include <atomic> #include <atomic>
#include <tuple> #include <tuple>
#include <pmmintrin.h> #include <pmmintrin.h>
#include <pthread.h>
#include <engine/Engine.hpp> #include <engine/Engine.hpp>
#include <settings.hpp> #include <settings.hpp>
@ -41,6 +40,7 @@
#include <random.hpp> #include <random.hpp>
#include <patch.hpp> #include <patch.hpp>
#include <plugin.hpp> #include <plugin.hpp>
#include <mutex.hpp>
#include <helpers.hpp> #include <helpers.hpp>
#ifdef NDEBUG #ifdef NDEBUG
@ -53,55 +53,6 @@ namespace rack {
namespace engine { namespace engine {
/** Allows multiple "reader" threads to obtain a lock simultaneously, but only one "writer" thread.
This implementation is currently just a wrapper for pthreads, which works on Linux/Mac/.
This is available in C++17 as std::shared_mutex, but unfortunately we're using C++11.
*/
struct ReadWriteMutex {
pthread_rwlock_t rwlock;
ReadWriteMutex() {
if (pthread_rwlock_init(&rwlock, nullptr))
throw Exception("pthread_rwlock_init failed");
}
~ReadWriteMutex() {
pthread_rwlock_destroy(&rwlock);
}
void lockReader() {
DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_rdlock(&rwlock) == 0,);
}
void unlockReader() {
DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_unlock(&rwlock) == 0,);
}
void lockWriter() {
DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_wrlock(&rwlock) == 0,);
}
void unlockWriter() {
DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_unlock(&rwlock) == 0,);
}
};
struct ReadLock {
ReadWriteMutex& m;
ReadLock(ReadWriteMutex& m) : m(m) {
m.lockReader();
}
~ReadLock() {
m.unlockReader();
}
};
struct WriteLock {
ReadWriteMutex& m;
WriteLock(ReadWriteMutex& m) : m(m) {
m.lockWriter();
}
~WriteLock() {
m.unlockWriter();
}
};
struct Engine::Internal { struct Engine::Internal {
std::vector<Module*> modules; std::vector<Module*> modules;
std::vector<Cable*> cables; std::vector<Cable*> cables;
@ -139,7 +90,7 @@ struct Engine::Internal {
Writers lock when mutating the engine's state or stepping the block. Writers lock when mutating the engine's state or stepping the block.
Readers lock when using the engine's state. Readers lock when using the engine's state.
*/ */
ReadWriteMutex mutex; SharedMutex mutex;
}; };
@ -329,7 +280,7 @@ Engine::~Engine() {
void Engine::clear() { void Engine::clear() {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
clear_NoLock(); clear_NoLock();
} }
@ -358,7 +309,7 @@ void Engine::stepBlock(int frames) {
// Start timer before locking // Start timer before locking
double startTime = system::getTime(); double startTime = system::getTime();
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
// Configure thread // Configure thread
random::init(); random::init();
@ -420,7 +371,7 @@ float Engine::getSampleRate() {
void Engine::setSampleRate(float sampleRate) { void Engine::setSampleRate(float sampleRate) {
if (sampleRate == internal->sampleRate) if (sampleRate == internal->sampleRate)
return; return;
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
internal->sampleRate = sampleRate; internal->sampleRate = sampleRate;
internal->sampleTime = 1.f / sampleRate; internal->sampleTime = 1.f / sampleRate;
@ -498,7 +449,7 @@ size_t Engine::getNumModules() {
size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
size_t i = 0; size_t i = 0;
for (Module* m : internal->modules) { for (Module* m : internal->modules) {
if (i >= len) if (i >= len)
@ -511,7 +462,7 @@ size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) {
std::vector<int64_t> Engine::getModuleIds() { std::vector<int64_t> Engine::getModuleIds() {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
std::vector<int64_t> moduleIds; std::vector<int64_t> moduleIds;
moduleIds.reserve(internal->modules.size()); moduleIds.reserve(internal->modules.size());
for (Module* m : internal->modules) { for (Module* m : internal->modules) {
@ -522,7 +473,7 @@ std::vector<int64_t> Engine::getModuleIds() {
void Engine::addModule(Module* module) { void Engine::addModule(Module* module) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
DISTRHO_SAFE_ASSERT_RETURN(module,); DISTRHO_SAFE_ASSERT_RETURN(module,);
// Check that the module is not already added // Check that the module is not already added
auto it = std::find(internal->modules.begin(), internal->modules.end(), module); auto it = std::find(internal->modules.begin(), internal->modules.end(), module);
@ -552,7 +503,7 @@ void Engine::addModule(Module* module) {
void Engine::removeModule(Module* module) { void Engine::removeModule(Module* module) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
removeModule_NoLock(module); removeModule_NoLock(module);
} }
@ -606,7 +557,7 @@ void Engine::removeModule_NoLock(Module* module) {
bool Engine::hasModule(Module* module) { bool Engine::hasModule(Module* module) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
// TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid.
auto it = std::find(internal->modules.begin(), internal->modules.end(), module); auto it = std::find(internal->modules.begin(), internal->modules.end(), module);
return it != internal->modules.end(); return it != internal->modules.end();
@ -614,7 +565,7 @@ bool Engine::hasModule(Module* module) {
Module* Engine::getModule(int64_t moduleId) { Module* Engine::getModule(int64_t moduleId) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
return getModule_NoLock(moduleId); return getModule_NoLock(moduleId);
} }
@ -628,7 +579,7 @@ Module* Engine::getModule_NoLock(int64_t moduleId) {
void Engine::resetModule(Module* module) { void Engine::resetModule(Module* module) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
DISTRHO_SAFE_ASSERT_RETURN(module,); DISTRHO_SAFE_ASSERT_RETURN(module,);
Module::ResetEvent eReset; Module::ResetEvent eReset;
@ -637,7 +588,7 @@ void Engine::resetModule(Module* module) {
void Engine::randomizeModule(Module* module) { void Engine::randomizeModule(Module* module) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
DISTRHO_SAFE_ASSERT_RETURN(module,); DISTRHO_SAFE_ASSERT_RETURN(module,);
Module::RandomizeEvent eRandomize; Module::RandomizeEvent eRandomize;
@ -650,7 +601,7 @@ void Engine::bypassModule(Module* module, bool bypassed) {
if (module->isBypassed() == bypassed) if (module->isBypassed() == bypassed)
return; return;
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
// Clear outputs and set to 1 channel // Clear outputs and set to 1 channel
for (Output& output : module->outputs) { for (Output& output : module->outputs) {
@ -673,26 +624,26 @@ void Engine::bypassModule(Module* module, bool bypassed) {
json_t* Engine::moduleToJson(Module* module) { json_t* Engine::moduleToJson(Module* module) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
return module->toJson(); return module->toJson();
} }
void Engine::moduleFromJson(Module* module, json_t* rootJ) { void Engine::moduleFromJson(Module* module, json_t* rootJ) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
module->fromJson(rootJ); module->fromJson(rootJ);
} }
void Engine::prepareSaveModule(Module* module) { void Engine::prepareSaveModule(Module* module) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
Module::SaveEvent e; Module::SaveEvent e;
module->onSave(e); module->onSave(e);
} }
void Engine::prepareSave() { void Engine::prepareSave() {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
for (Module* module : internal->modules) { for (Module* module : internal->modules) {
Module::SaveEvent e; Module::SaveEvent e;
module->onSave(e); module->onSave(e);
@ -706,7 +657,7 @@ size_t Engine::getNumCables() {
size_t Engine::getCableIds(int64_t* cableIds, size_t len) { size_t Engine::getCableIds(int64_t* cableIds, size_t len) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
size_t i = 0; size_t i = 0;
for (Cable* c : internal->cables) { for (Cable* c : internal->cables) {
if (i >= len) if (i >= len)
@ -719,7 +670,7 @@ size_t Engine::getCableIds(int64_t* cableIds, size_t len) {
std::vector<int64_t> Engine::getCableIds() { std::vector<int64_t> Engine::getCableIds() {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
std::vector<int64_t> cableIds; std::vector<int64_t> cableIds;
cableIds.reserve(internal->cables.size()); cableIds.reserve(internal->cables.size());
for (Cable* c : internal->cables) { for (Cable* c : internal->cables) {
@ -730,7 +681,7 @@ std::vector<int64_t> Engine::getCableIds() {
void Engine::addCable(Cable* cable) { void Engine::addCable(Cable* cable) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
DISTRHO_SAFE_ASSERT_RETURN(cable,); DISTRHO_SAFE_ASSERT_RETURN(cable,);
// Check cable properties // Check cable properties
DISTRHO_SAFE_ASSERT_RETURN(cable->inputModule,); DISTRHO_SAFE_ASSERT_RETURN(cable->inputModule,);
@ -775,7 +726,7 @@ void Engine::addCable(Cable* cable) {
void Engine::removeCable(Cable* cable) { void Engine::removeCable(Cable* cable) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
removeCable_NoLock(cable); removeCable_NoLock(cable);
} }
@ -816,7 +767,7 @@ void Engine::removeCable_NoLock(Cable* cable) {
bool Engine::hasCable(Cable* cable) { bool Engine::hasCable(Cable* cable) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
// TODO Performance could be improved by searching cablesCache, but more testing would be needed to make sure it's always valid. // TODO Performance could be improved by searching cablesCache, but more testing would be needed to make sure it's always valid.
auto it = std::find(internal->cables.begin(), internal->cables.end(), cable); auto it = std::find(internal->cables.begin(), internal->cables.end(), cable);
return it != internal->cables.end(); return it != internal->cables.end();
@ -824,7 +775,7 @@ bool Engine::hasCable(Cable* cable) {
Cable* Engine::getCable(int64_t cableId) { Cable* Engine::getCable(int64_t cableId) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
auto it = internal->cablesCache.find(cableId); auto it = internal->cablesCache.find(cableId);
if (it == internal->cablesCache.end()) if (it == internal->cablesCache.end())
return NULL; return NULL;
@ -867,7 +818,7 @@ float Engine::getParamSmoothValue(Module* module, int paramId) {
void Engine::addParamHandle(ParamHandle* paramHandle) { void Engine::addParamHandle(ParamHandle* paramHandle) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
// New ParamHandles must be blank. // New ParamHandles must be blank.
// This means we don't have to refresh the cache. // This means we don't have to refresh the cache.
DISTRHO_SAFE_ASSERT_RETURN(paramHandle->moduleId < 0,); DISTRHO_SAFE_ASSERT_RETURN(paramHandle->moduleId < 0,);
@ -883,7 +834,7 @@ void Engine::addParamHandle(ParamHandle* paramHandle) {
void Engine::removeParamHandle(ParamHandle* paramHandle) { void Engine::removeParamHandle(ParamHandle* paramHandle) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
removeParamHandle_NoLock(paramHandle); removeParamHandle_NoLock(paramHandle);
} }
@ -901,7 +852,7 @@ void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) {
ParamHandle* Engine::getParamHandle(int64_t moduleId, int paramId) { ParamHandle* Engine::getParamHandle(int64_t moduleId, int paramId) {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
return getParamHandle_NoLock(moduleId, paramId); return getParamHandle_NoLock(moduleId, paramId);
} }
@ -920,7 +871,7 @@ ParamHandle* Engine::getParamHandle(Module* module, int paramId) {
void Engine::updateParamHandle(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { void Engine::updateParamHandle(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) {
WriteLock lock(internal->mutex); std::lock_guard<SharedMutex> lock(internal->mutex);
updateParamHandle_NoLock(paramHandle, moduleId, paramId, overwrite); updateParamHandle_NoLock(paramHandle, moduleId, paramId, overwrite);
} }
@ -963,7 +914,7 @@ void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId
json_t* Engine::toJson() { json_t* Engine::toJson() {
ReadLock lock(internal->mutex); SharedLock<SharedMutex> lock(internal->mutex);
json_t* rootJ = json_object(); json_t* rootJ = json_object();
// modules // modules

View file

@ -143,6 +143,7 @@ struct Window::Internal {
std::map<std::string, std::shared_ptr<ImageWithOriginalContext>> imageCache; std::map<std::string, std::shared_ptr<ImageWithOriginalContext>> imageCache;
bool fbDirtyOnSubpixelChange = true; bool fbDirtyOnSubpixelChange = true;
int fbCount = 0;
Internal() Internal()
: hiddenApp(false), : hiddenApp(false),
@ -343,6 +344,7 @@ void Window::step() {
double lastFrameTime = internal->frameTime; double lastFrameTime = internal->frameTime;
internal->frameTime = frameTime; internal->frameTime = frameTime;
internal->lastFrameDuration = frameTime - lastFrameTime; internal->lastFrameDuration = frameTime - lastFrameTime;
internal->fbCount = 0;
// DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration);
// Make event handlers and step() have a clean NanoVG context // Make event handlers and step() have a clean NanoVG context
@ -515,6 +517,11 @@ bool& Window::fbDirtyOnSubpixelChange() {
} }
int& Window::fbCount() {
return internal->fbCount;
}
} // namespace window } // namespace window
} // namespace rack } // namespace rack