diff --git a/3rdparty/avendish b/3rdparty/avendish index 76069c9a97..5dce117550 160000 --- a/3rdparty/avendish +++ b/3rdparty/avendish @@ -1 +1 @@ -Subproject commit 76069c9a9752baca9dfa8440a27f9dd4c1788a46 +Subproject commit 5dce1175508b20c9b0e7077d22345813e890f452 diff --git a/3rdparty/libossia b/3rdparty/libossia index 1830ebd233..e77c0e0856 160000 --- a/3rdparty/libossia +++ b/3rdparty/libossia @@ -1 +1 @@ -Subproject commit 1830ebd23367a106021eab033c8e4ac0a13f0f52 +Subproject commit e77c0e0856650421dc946725430131897a04cd09 diff --git a/src/plugins/score-plugin-avnd/CMakeLists.txt b/src/plugins/score-plugin-avnd/CMakeLists.txt index cd22fa65fb..6b762d0786 100644 --- a/src/plugins/score-plugin-avnd/CMakeLists.txt +++ b/src/plugins/score-plugin-avnd/CMakeLists.txt @@ -512,6 +512,14 @@ avnd_make_score( NAMESPACE ao ) +avnd_make_score( + SOURCES "${AVND_FOLDER}/examples/Advanced/Utilities/LightnessSampler.hpp" + TARGET lightness_sampler + MAIN_CLASS LightnessSampler + NAMESPACE vo +) + + avnd_make_score( SOURCES "${AVND_FOLDER}/examples/Gpu/SolidColor.hpp" TARGET gpu_solid_color diff --git a/src/plugins/score-plugin-avnd/Crousti/CpuAnalysisNode.hpp b/src/plugins/score-plugin-avnd/Crousti/CpuAnalysisNode.hpp index ffa2523fc4..915c567c8c 100644 --- a/src/plugins/score-plugin-avnd/Crousti/CpuAnalysisNode.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/CpuAnalysisNode.hpp @@ -165,9 +165,12 @@ template && avnd::texture_output_introspection::size == 0) struct GfxNode final : CustomGpuOutputNodeBase { + oscr::ProcessModel& processModel; GfxNode( + oscr::ProcessModel& element, std::weak_ptr q, Gfx::exec_controls ctls, int id) : CustomGpuOutputNodeBase{std::move(q), std::move(ctls)} + , processModel{element} { this->instance = id; diff --git a/src/plugins/score-plugin-avnd/Crousti/CpuFilterNode.hpp b/src/plugins/score-plugin-avnd/Crousti/CpuFilterNode.hpp index f3b6fe0b5f..7ef64f22b6 100644 --- a/src/plugins/score-plugin-avnd/Crousti/CpuFilterNode.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/CpuFilterNode.hpp @@ -297,9 +297,12 @@ struct GfxNode final : CustomGfxNodeBase , GpuControlOuts { + oscr::ProcessModel& processModel; GfxNode( + oscr::ProcessModel& element, std::weak_ptr q, Gfx::exec_controls ctls, int id) : GpuControlOuts{std::move(q), std::move(ctls)} + , processModel{element} { this->instance = id; @@ -325,6 +328,5 @@ struct GfxNode final return new GfxRenderer{*this}; } }; - } #endif diff --git a/src/plugins/score-plugin-avnd/Crousti/CpuGeneratorNode.hpp b/src/plugins/score-plugin-avnd/Crousti/CpuGeneratorNode.hpp index 6902c94ca8..0e418e5450 100644 --- a/src/plugins/score-plugin-avnd/Crousti/CpuGeneratorNode.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/CpuGeneratorNode.hpp @@ -205,9 +205,12 @@ struct GfxNode final : CustomGfxNodeBase , GpuControlOuts { + oscr::ProcessModel& processModel; GfxNode( + oscr::ProcessModel& element, std::weak_ptr q, Gfx::exec_controls ctls, int id) : GpuControlOuts{std::move(q), std::move(ctls)} + , processModel{element} { this->instance = id; @@ -227,6 +230,5 @@ struct GfxNode final return new GfxRenderer{*this}; } }; - } #endif diff --git a/src/plugins/score-plugin-avnd/Crousti/Executor.hpp b/src/plugins/score-plugin-avnd/Crousti/Executor.hpp index 134e9165d5..e9a9642b89 100644 --- a/src/plugins/score-plugin-avnd/Crousti/Executor.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/Executor.hpp @@ -615,15 +615,18 @@ class Executor final std::unique_ptr ptr; if constexpr(GpuGraphicsNode2) { - ptr.reset(new CustomGpuNode(qex_ptr, node->control_outs, id)); + auto gpu_node = new CustomGpuNode(qex_ptr, node->control_outs, id); + ptr.reset(gpu_node); } else if constexpr(GpuComputeNode2) { - ptr.reset(new GpuComputeNode(qex_ptr, node->control_outs, id)); + auto gpu_node = new GpuComputeNode(qex_ptr, node->control_outs, id); + ptr.reset(gpu_node); } else if constexpr(GpuNode) { - ptr.reset(new GfxNode(qex_ptr, node->control_outs, id)); + auto gpu_node = new GfxNode(element, qex_ptr, node->control_outs, id); + ptr.reset(gpu_node); } node->id = gfx_exec.ui->register_node(std::move(ptr)); node_id = node->id; @@ -640,7 +643,9 @@ class Executor final ptr.reset(node); this->node = ptr; - connect_message_bus(element, ctx, ptr); + if constexpr(requires { ptr->impl.effect; }) + if constexpr(std::is_same_vimpl.effect)>, Node>) + connect_message_bus(element, ctx, ptr->impl.effect); connect_worker(element, ctx, ptr); node->finish_init(); @@ -722,33 +727,31 @@ class Executor final } void connect_message_bus( - ProcessModel& element, const ::Execution::Context& ctx, - std::shared_ptr>& ptr) + ProcessModel& element, const ::Execution::Context& ctx, Node& eff) { // Custom UI messages to engine - avnd::effect_container& eff = ptr->impl; if constexpr(avnd::has_gui_to_processor_bus) { element.from_ui = [p = QPointer{this}, &eff](QByteArray b) { if(!p) return; - p->in_exec([mess = std::move(b), &eff] { + p->in_exec([mess = std::move(b), &eff]() mutable { using refl = avnd::function_reflection<&Node::process_message>; static_assert(refl::count <= 1); if constexpr(refl::count == 0) { // no arguments, just call it - eff.effect.process_message(); + eff.process_message(); } else if constexpr(refl::count == 1) { using arg_type = avnd::first_argument<&Node::process_message>; std::decay_t arg; - MessageBusReader b{mess}; - b(arg); - eff.effect.process_message(std::move(arg)); + MessageBusReader reader{mess}; + reader(arg); + eff.process_message(std::move(arg)); } }); }; @@ -756,7 +759,7 @@ class Executor final if constexpr(avnd::has_processor_to_gui_bus) { - eff.effect.send_message = [this](auto b) mutable { + eff.send_message = [this](auto b) mutable { this->in_edit([this, bb = std::move(b)]() mutable { MessageBusSender{this->process().to_ui}(std::move(bb)); }); diff --git a/src/plugins/score-plugin-avnd/Crousti/GfxNode.hpp b/src/plugins/score-plugin-avnd/Crousti/GfxNode.hpp index c1bbfe54be..1ae060b2b5 100644 --- a/src/plugins/score-plugin-avnd/Crousti/GfxNode.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/GfxNode.hpp @@ -11,8 +11,11 @@ #include #include + namespace oscr { +template +class ProcessModel; static const constexpr auto generic_texgen_vs = R"_(#version 450 layout(location = 0) in vec2 position; layout(location = 1) in vec2 texcoord; diff --git a/src/plugins/score-plugin-avnd/Crousti/GpuUtils.cpp b/src/plugins/score-plugin-avnd/Crousti/GpuUtils.cpp index 90b10b85d8..2844f7812b 100644 --- a/src/plugins/score-plugin-avnd/Crousti/GpuUtils.cpp +++ b/src/plugins/score-plugin-avnd/Crousti/GpuUtils.cpp @@ -52,12 +52,16 @@ CustomGpuOutputNodeBase::CustomGpuOutputNodeBase( m_renderState->rhi = QRhi::create(QRhi::OpenGLES2, ¶ms); } - m_renderState->renderSize = QSize(1000, 1000); - m_renderState->outputSize = QSize(1000, 1000); + m_renderState->renderSize = QSize(200, 200); + m_renderState->outputSize = QSize(200, 200); m_renderState->api = score::gfx::GraphicsApi::OpenGL; m_renderState->version = caps.qShaderVersion; } -CustomGpuOutputNodeBase::~CustomGpuOutputNodeBase() = default; + +CustomGpuOutputNodeBase::~CustomGpuOutputNodeBase() +{ + m_renderState->destroy(); +} void CustomGpuOutputNodeBase::process(score::gfx::Message&& msg) { @@ -66,7 +70,6 @@ void CustomGpuOutputNodeBase::process(score::gfx::Message&& msg) void CustomGpuOutputNodeBase::setRenderer(std::shared_ptr r) { - m_renderer = r; } @@ -79,7 +82,6 @@ void CustomGpuOutputNodeBase::startRendering() { } void CustomGpuOutputNodeBase::render() { - if(m_update) m_update(); diff --git a/src/plugins/score-plugin-avnd/Crousti/GpuUtils.hpp b/src/plugins/score-plugin-avnd/Crousti/GpuUtils.hpp index 65d7551024..f43a752105 100644 --- a/src/plugins/score-plugin-avnd/Crousti/GpuUtils.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/GpuUtils.hpp @@ -3,6 +3,7 @@ #if SCORE_PLUGIN_GFX #include +#include #include #include #include @@ -916,17 +917,29 @@ struct SCORE_PLUGIN_AVND_EXPORT CustomGpuOutputNodeBase }; template -void prepareNewState(Node_T& node, const Node& parent) +void prepareNewState(Node_T& eff, const Node& parent) { + if constexpr(avnd::has_processor_to_gui_bus) + { + auto& process = parent.processModel; + eff.send_message = [&process](auto&& b) mutable { + // FIXME right now all the rendering is done in the UI thread, which is very MEH + // this->in_edit([&process, bb = std::move(b)]() mutable { + MessageBusSender{process.to_ui}(std::move(b)); + // }); + }; + + // FIXME GUI -> engine. See executor.hpp + } + if constexpr(avnd::can_prepare) { using prepare_type = avnd::first_argument<&Node_T::prepare>; prepare_type t; if_possible(t.instance = parent.instance); - node.prepare(t); + eff.prepare(t); } } - } #endif diff --git a/src/plugins/score-plugin-avnd/Crousti/Layer.hpp b/src/plugins/score-plugin-avnd/Crousti/Layer.hpp index 774cec7e6f..165f3842e9 100644 --- a/src/plugins/score-plugin-avnd/Crousti/Layer.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/Layer.hpp @@ -339,7 +339,11 @@ class LayerFactory final : public Process::LayerFactory if constexpr(avnd::has_processor_to_gui_bus) { // engine -> ui - proc.to_ui = [ptr](QByteArray mess) { + proc.to_ui = [ptr = QPointer{ptr}](QByteArray mess) { + // FIXME this is not enough as the message may be sent from another thread? + if(!ptr) + return; + if constexpr(requires { ptr->bus.process_message(); }) { ptr->bus.process_message(); @@ -350,7 +354,7 @@ class LayerFactory final : public Process::LayerFactory } else if constexpr(requires { ptr->bus.process_message(ptr->ui, {}); }) { - avnd::second_argument<&Info::ui::bus::process_message> arg; + std::decay_t> arg; MessageBusReader b{mess}; b(arg); ptr->bus.process_message(ptr->ui, std::move(arg)); diff --git a/src/plugins/score-plugin-avnd/Crousti/MessageBus.hpp b/src/plugins/score-plugin-avnd/Crousti/MessageBus.hpp index 5297fee249..5a294e247c 100644 --- a/src/plugins/score-plugin-avnd/Crousti/MessageBus.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/MessageBus.hpp @@ -3,6 +3,9 @@ #include +#include +#include + namespace oscr { @@ -43,7 +46,30 @@ struct MessageBusSender } template - requires(!std::is_trivial_v) void operator()(const T& msg) + requires(!std::is_trivial_v && avnd::relocatable) + void operator()(const T& msg) + { + QByteArray b(msg.size(), Qt::Uninitialized); + auto dst = reinterpret_cast(b.data()); + new(dst) T(msg); + + this->bus(std::move(b)); + } + + template + requires(!std::is_trivial_v && avnd::relocatable) + void operator()(T&& msg) + { + QByteArray b(sizeof(msg), Qt::Uninitialized); + auto dst = reinterpret_cast(b.data()); + std::construct_at(dst, std::move(msg)); + + this->bus(std::move(b)); + } + + template + requires(!std::is_trivial_v && !avnd::relocatable) + void operator()(const T& msg) { // Here we gotta serialize... :D QByteArray buf; @@ -51,7 +77,7 @@ struct MessageBusSender DataStreamReader str{&buf}; Serializer{str}(msg); - this->bus(buf); + this->bus(std::move(buf)); } }; @@ -92,7 +118,7 @@ struct Deserializer struct MessageBusReader { - const QByteArray& mess; + QByteArray& mess; template requires std::is_trivial_v @@ -101,9 +127,18 @@ struct MessageBusReader // Here we can just do a memcpy memcpy(&msg, mess.data(), mess.size()); } + template + requires(!std::is_trivial_v && avnd::relocatable) + void operator()(T& msg) + { + auto src = reinterpret_cast(mess.data()); + msg = std::move(*src); + std::destroy_at(src); + } template - requires(!std::is_trivial_v) void operator()(T& msg) + requires(!std::is_trivial_v && !avnd::relocatable) + void operator()(T& msg) { // Deserialize... :D diff --git a/src/plugins/score-plugin-avnd/Crousti/Painter.hpp b/src/plugins/score-plugin-avnd/Crousti/Painter.hpp index 5874560d8f..e9458f9a08 100644 --- a/src/plugins/score-plugin-avnd/Crousti/Painter.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/Painter.hpp @@ -174,6 +174,12 @@ struct QPainterAdapter } path.addPolygon(poly); } + + void draw_bytes(int x, int y, int w, int h, unsigned char* image, int img_w, int img_h) + { + auto img = QImage(image, img_w, img_h, QImage::Format_RGB32); + painter.drawImage(QRect(x, y, w, h), img, QRect(0, 0, img_w, img_h)); + } }; static_assert(avnd::painter); diff --git a/src/plugins/score-plugin-gfx/Gfx/Graph/RenderState.hpp b/src/plugins/score-plugin-gfx/Gfx/Graph/RenderState.hpp index 28dcee8b97..b67b77227f 100644 --- a/src/plugins/score-plugin-gfx/Gfx/Graph/RenderState.hpp +++ b/src/plugins/score-plugin-gfx/Gfx/Graph/RenderState.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) @@ -44,5 +45,14 @@ struct RenderState int samples{1}; GraphicsApi api{}; QShaderVersion version{}; + + void destroy() + { + delete rhi; + rhi = nullptr; + + delete surface; + surface = nullptr; + } }; } diff --git a/src/plugins/score-plugin-gfx/Gfx/Graph/ScreenNode.cpp b/src/plugins/score-plugin-gfx/Gfx/Graph/ScreenNode.cpp index 4823f65f3e..9c3ab0ff9b 100644 --- a/src/plugins/score-plugin-gfx/Gfx/Graph/ScreenNode.cpp +++ b/src/plugins/score-plugin-gfx/Gfx/Graph/ScreenNode.cpp @@ -420,11 +420,7 @@ void ScreenNode::destroyOutput() if(auto s = m_window->state) { - delete s->rhi; - s->rhi = nullptr; - - delete s->surface; - s->surface = nullptr; + s->destroy(); } if(m_ownsWindow)