4#include <Process/ExecutionContext.hpp>
6#include <Crousti/File.hpp>
7#include <Crousti/MessageBus.hpp>
8#include <Gfx/GfxExecNode.hpp>
9#include <Gfx/Graph/Node.hpp>
10#include <Gfx/Graph/OutputNode.hpp>
11#include <Gfx/Graph/RenderState.hpp>
13#include <score/tools/ThreadPool.hpp>
15#include <ossia-qt/invoke.hpp>
17#include <QCoreApplication>
19#include <QtGui/private/qrhi_p.h>
21#include <avnd/binding/ossia/port_run_postprocess.hpp>
22#include <avnd/binding/ossia/port_run_preprocess.hpp>
23#include <avnd/binding/ossia/soundfiles.hpp>
24#include <avnd/concepts/parameter.hpp>
25#include <avnd/introspection/input.hpp>
26#include <avnd/introspection/output.hpp>
27#include <fmt/format.h>
28#include <gpp/layout.hpp>
30#include <score_plugin_avnd_export.h>
35constexpr QRhiTexture::Format textureFormat()
37 if constexpr(
requires { std::string_view{F::format()}; })
39 constexpr std::string_view fmt = F::format();
41 if(fmt ==
"rgba" || fmt ==
"rgba8")
42 return QRhiTexture::RGBA8;
43 else if(fmt ==
"bgra" || fmt ==
"bgra8")
44 return QRhiTexture::BGRA8;
46 return QRhiTexture::R8;
47#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
49 return QRhiTexture::RG8;
52 return QRhiTexture::R16;
53#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
54 else if(fmt ==
"rg16")
55 return QRhiTexture::RG16;
57 else if(fmt ==
"red_or_alpha8")
58 return QRhiTexture::RED_OR_ALPHA8;
59 else if(fmt ==
"rgba16f")
60 return QRhiTexture::RGBA16F;
61 else if(fmt ==
"rgba32f")
62 return QRhiTexture::RGBA32F;
63 else if(fmt ==
"r16f")
64 return QRhiTexture::R16F;
66 return QRhiTexture::R32F;
67#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
68 else if(fmt ==
"rgb10a2")
69 return QRhiTexture::RGB10A2;
73 return QRhiTexture::D16;
75#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
77 return QRhiTexture::D24;
78 else if(fmt ==
"d24s8")
79 return QRhiTexture::D24S8;
81 else if(fmt ==
"d32f")
82 return QRhiTexture::D32F;
85 return QRhiTexture::BC1;
87 return QRhiTexture::BC2;
89 return QRhiTexture::BC3;
91 return QRhiTexture::BC4;
93 return QRhiTexture::BC5;
94 else if(fmt ==
"bc6h")
95 return QRhiTexture::BC6H;
97 return QRhiTexture::BC7;
98 else if(fmt ==
"etc2_rgb8")
99 return QRhiTexture::ETC2_RGB8;
100 else if(fmt ==
"etc2_rgb8a1")
101 return QRhiTexture::ETC2_RGB8A1;
102 else if(fmt ==
"etc2_rgb8a8")
103 return QRhiTexture::ETC2_RGBA8;
104 else if(fmt ==
"astc_4x4")
105 return QRhiTexture::ASTC_4x4;
106 else if(fmt ==
"astc_5x4")
107 return QRhiTexture::ASTC_5x4;
108 else if(fmt ==
"astc_5x5")
109 return QRhiTexture::ASTC_5x5;
110 else if(fmt ==
"astc_6x5")
111 return QRhiTexture::ASTC_6x5;
112 else if(fmt ==
"astc_6x6")
113 return QRhiTexture::ASTC_6x6;
114 else if(fmt ==
"astc_8x5")
115 return QRhiTexture::ASTC_8x5;
116 else if(fmt ==
"astc_8x6")
117 return QRhiTexture::ASTC_8x6;
118 else if(fmt ==
"astc_8x8")
119 return QRhiTexture::ASTC_8x8;
120 else if(fmt ==
"astc_10x5")
121 return QRhiTexture::ASTC_10x5;
122 else if(fmt ==
"astc_10x6")
123 return QRhiTexture::ASTC_10x6;
124 else if(fmt ==
"astc_10x8")
125 return QRhiTexture::ASTC_10x8;
126 else if(fmt ==
"astc_10x10")
127 return QRhiTexture::ASTC_10x10;
128 else if(fmt ==
"astc_12x10")
129 return QRhiTexture::ASTC_12x10;
130 else if(fmt ==
"astc_12x12")
131 return QRhiTexture::ASTC_12x12;
133 return QRhiTexture::RGBA8;
135 else if constexpr(std::is_enum_v<typename F::format>)
137 if constexpr(
requires { F::RGBA; } ||
requires { F::RGBA8; })
138 return QRhiTexture::RGBA8;
139 else if constexpr(
requires { F::BGRA; } ||
requires { F::BGRA8; })
140 return QRhiTexture::BGRA8;
141 else if constexpr(
requires { F::R8; } ||
requires { F::GRAYSCALE; })
142 return QRhiTexture::R8;
143#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
144 else if constexpr(
requires { F::RG8; })
145 return QRhiTexture::RG8;
147 else if constexpr(
requires { F::R16; })
148 return QRhiTexture::R16;
149#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
150 else if constexpr(
requires { F::RG16; })
151 return QRhiTexture::RG16;
153 else if constexpr(
requires { F::RED_OR_ALPHA8; })
154 return QRhiTexture::RED_OR_ALPHA8;
155 else if constexpr(
requires { F::RGBA16F; })
156 return QRhiTexture::RGBA16F;
157 else if constexpr(
requires { F::RGBA32F; })
158 return QRhiTexture::RGBA32F;
159 else if constexpr(
requires { F::R16F; })
160 return QRhiTexture::R16F;
161 else if constexpr(
requires { F::R32F; })
162 return QRhiTexture::R32F;
163#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
164 else if constexpr(
requires { F::RGB10A2; })
165 return QRhiTexture::RGB10A2;
167 else if constexpr(
requires { F::D16; })
168 return QRhiTexture::D16;
170#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
171 else if constexpr(
requires { F::D24; })
172 return QRhiTexture::D24;
173 else if constexpr(
requires { F::D24S8; })
174 return QRhiTexture::D24S8;
176 else if constexpr(
requires { F::D32F; })
177 return QRhiTexture::D32F;
179 else if constexpr(
requires { F::BC1; })
180 return QRhiTexture::BC1;
181 else if constexpr(
requires { F::BC2; })
182 return QRhiTexture::BC2;
183 else if constexpr(
requires { F::BC3; })
184 return QRhiTexture::BC3;
185 else if constexpr(
requires { F::BC4; })
186 return QRhiTexture::BC4;
187 else if constexpr(
requires { F::BC5; })
188 return QRhiTexture::BC5;
189 else if constexpr(
requires { F::BC6H; })
190 return QRhiTexture::BC6H;
191 else if constexpr(
requires { F::BC7; })
192 return QRhiTexture::BC7;
193 else if(
requires { F::ETC2_RGB8; })
194 return QRhiTexture::ETC2_RGB8;
195 else if(
requires { F::ETC2_RGB8A1; })
196 return QRhiTexture::ETC2_RGB8A1;
197 else if(
requires { F::ETC2_RGB8A8; })
198 return QRhiTexture::ETC2_RGBA8;
199 else if(
requires { F::ASTC_4X4; })
200 return QRhiTexture::ASTC_4x4;
201 else if(
requires { F::ASTC_5X4; })
202 return QRhiTexture::ASTC_5x4;
203 else if(
requires { F::ASTC_5X5; })
204 return QRhiTexture::ASTC_5x5;
205 else if(
requires { F::ASTC_6X5; })
206 return QRhiTexture::ASTC_6x5;
207 else if(
requires { F::ASTC_6X6; })
208 return QRhiTexture::ASTC_6x6;
209 else if(
requires { F::ASTC_8X5; })
210 return QRhiTexture::ASTC_8x5;
211 else if(
requires { F::ASTC_8X6; })
212 return QRhiTexture::ASTC_8x6;
213 else if(
requires { F::ASTC_8X8; })
214 return QRhiTexture::ASTC_8x8;
215 else if(
requires { F::ASTC_10X5; })
216 return QRhiTexture::ASTC_10x5;
217 else if(
requires { F::ASTC_10X6; })
218 return QRhiTexture::ASTC_10x6;
219 else if(
requires { F::ASTC_10X8; })
220 return QRhiTexture::ASTC_10x8;
221 else if(
requires { F::ASTC_10X10; })
222 return QRhiTexture::ASTC_10x10;
223 else if(
requires { F::ASTC_12X10; })
224 return QRhiTexture::ASTC_12x10;
225 else if(
requires { F::ASTC_12X12; })
226 return QRhiTexture::ASTC_12x12;
228 return QRhiTexture::RGBA8;
232struct DefaultPipeline
244 static constexpr auto name() {
return "position"; }
245 static constexpr int location() {
return 0; }
252 struct fragment_input
260 static QString vertex()
262 return R
"_(#version 450
263layout(location = 0) in vec2 position;
264out gl_PerVertex { vec4 gl_Position; };
266 gl_Position = vec4( position, 0.0, 1.0 );
273constexpr auto usage()
275 if constexpr(
requires { C::vertex; })
276 return QRhiBuffer::VertexBuffer;
277 else if constexpr(
requires { C::index; })
278 return QRhiBuffer::IndexBuffer;
279 else if constexpr(
requires { C::ubo; })
280 return QRhiBuffer::UniformBuffer;
281 else if constexpr(
requires { C::storage; })
282 return QRhiBuffer::StorageBuffer;
285 static_assert(C::unhandled);
291constexpr auto buffer_type()
293 if constexpr(
requires { C::immutable; })
294 return QRhiBuffer::Immutable;
295 else if constexpr(
requires { C::static_; })
296 return QRhiBuffer::Static;
297 else if constexpr(
requires { C::dynamic; })
298 return QRhiBuffer::Dynamic;
301 static_assert(C::unhandled);
309 if constexpr(
requires { C::samples; })
318 template <
typename C>
319 void operator()(C command)
321 if constexpr(
requires { C::deallocation; })
324 requires { C::vertex; } ||
requires { C::index; } ||
requires { C::ubo; })
326 auto buf =
reinterpret_cast<QRhiBuffer*
>(command.handle);
329 else if constexpr(
requires { C::sampler; })
331 auto buf =
reinterpret_cast<QRhiSampler*
>(command.handle);
334 else if constexpr(
requires { C::texture; })
336 auto buf =
reinterpret_cast<QRhiTexture*
>(command.handle);
341 static_assert(C::unhandled);
346 static_assert(C::unhandled);
351template <
typename Self,
typename Res>
352struct handle_dispatch
356 QRhiCommandBuffer& cb;
357 QRhiResourceUpdateBatch*& res;
358 QRhiComputePipeline& pip;
359 template <
typename C>
360 Res operator()(C command)
362 if constexpr(
requires { C::compute; })
364 if constexpr(
requires { C::dispatch; })
366 cb.dispatch(command.x, command.y, command.z);
369 else if constexpr(
requires { C::begin; })
371 cb.beginComputePass(res);
373 cb.setComputePipeline(&pip);
374 cb.setShaderResources(pip.shaderResourceBindings());
378 else if constexpr(
requires { C::end; })
380 cb.endComputePass(res);
387 static_assert(C::unhandled);
391 else if constexpr(
requires { C::readback; })
394 if constexpr(
requires { C::request; })
396 if constexpr(
requires { C::buffer; })
398 using ret =
typename C::return_type;
400#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
401 auto readback =
new QRhiBufferReadbackResult;
403 auto readback =
new QRhiReadbackResult;
405 self.addReadback(readback);
408 ret user_rb{.handle =
reinterpret_cast<decltype(ret::handle)
>(readback)};
419 auto next = rhi.nextResourceUpdateBatch();
420 auto buf =
reinterpret_cast<QRhiBuffer*
>(command.handle);
422 next->readBackBuffer(buf, command.offset, command.size, readback);
427 else if constexpr(
requires { C::texture; })
429 using ret =
typename C::return_type;
430 QRhiReadbackResult readback;
435 static_assert(C::unhandled);
439 else if constexpr(
requires { C::await; })
441 if constexpr(
requires { C::buffer; })
443 using ret =
typename C::return_type;
445#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
446 auto readback =
reinterpret_cast<QRhiBufferReadbackResult*
>(command.handle);
448 auto readback =
reinterpret_cast<QRhiReadbackResult*
>(command.handle);
452 .data = readback->data.data(), .size = (std::size_t)readback->data.size()};
454 else if constexpr(
requires { C::texture; })
456 using ret =
typename C::return_type;
458 auto readback =
reinterpret_cast<QRhiReadbackResult*
>(command.handle);
461 .data = readback->data.data(), .size = (std::size_t)readback->data.size()};
467 static_assert(C::unhandled);
475template <
typename Self,
typename Ret>
480 QRhiResourceUpdateBatch& res;
481 std::vector<QRhiShaderResourceBinding>& srb;
484 template <
typename C>
485 Ret operator()(C command)
487 if constexpr(
requires { C::allocation; })
490 requires { C::vertex; } ||
requires { C::index; })
492 auto buf = rhi.newBuffer(buffer_type<C>(), usage<C>(), command.size);
494 return reinterpret_cast<typename C::return_type
>(buf);
496 else if constexpr(
requires { C::sampler; })
498 auto buf = rhi.newSampler({}, {}, {}, {}, {});
500 return reinterpret_cast<typename C::return_type
>(buf);
503 requires { C::ubo; } ||
requires { C::storage; })
505 auto buf = rhi.newBuffer(buffer_type<C>(), usage<C>(), command.size);
509 score::gfx::replaceBuffer(srb, command.binding, buf);
511 return reinterpret_cast<typename C::return_type
>(buf);
513 else if constexpr(
requires { C::texture; })
515 auto tex = rhi.newTexture(
516 QRhiTexture::RGBA8, QSize{command.width, command.height}, samples(command));
519 score::gfx::replaceTexture(srb, command.binding, tex);
521 return reinterpret_cast<typename C::return_type
>(tex);
525 static_assert(C::unhandled);
529 else if constexpr(
requires { C::upload; })
531 if constexpr(
requires { C::texture; })
533 QRhiTextureSubresourceUploadDescription sub(command.data, command.size);
535 reinterpret_cast<QRhiTexture*
>(command.handle),
536 QRhiTextureUploadDescription{{0, 0, sub}});
540 auto buf =
reinterpret_cast<QRhiBuffer*
>(command.handle);
541 if constexpr(
requires { C::dynamic; })
542 res.updateDynamicBuffer(buf, command.offset, command.size, command.data);
544 requires { C::static_; } ||
requires { C::immutable; })
545 res.uploadStaticBuffer(buf, command.offset, command.size, command.data);
548 static_assert(C::unhandled);
553 else if constexpr(
requires { C::getter; })
555 if constexpr(
requires { C::ubo; })
557 auto buf = self.createdUbos.at(command.binding);
558 return reinterpret_cast<typename C::return_type
>(buf);
562 static_assert(C::unhandled);
568 handle_release{rhi}(command);
575struct generate_shaders
577 template <
typename T,
int N>
580 static constexpr std::string_view field_type(
float) {
return "float"; }
581 static constexpr std::string_view field_type(
const float (&)[2]) {
return "vec2"; }
582 static constexpr std::string_view field_type(
const float (&)[3]) {
return "vec3"; }
583 static constexpr std::string_view field_type(
const float (&)[4]) {
return "vec4"; }
585 static constexpr std::string_view field_type(
float*) {
return "float"; }
586 static constexpr std::string_view field_type(vec<float, 2>*) {
return "vec2"; }
587 static constexpr std::string_view field_type(vec<float, 3>*) {
return "vec3"; }
588 static constexpr std::string_view field_type(vec<float, 4>*) {
return "vec4"; }
590 static constexpr std::string_view field_type(
int) {
return "int"; }
591 static constexpr std::string_view field_type(
const int (&)[2]) {
return "ivec2"; }
592 static constexpr std::string_view field_type(
const int (&)[3]) {
return "ivec3"; }
593 static constexpr std::string_view field_type(
const int (&)[4]) {
return "ivec4"; }
595 static constexpr std::string_view field_type(
int*) {
return "int"; }
596 static constexpr std::string_view field_type(vec<int, 2>*) {
return "ivec2"; }
597 static constexpr std::string_view field_type(vec<int, 3>*) {
return "ivec3"; }
598 static constexpr std::string_view field_type(vec<int, 4>*) {
return "ivec4"; }
600 static constexpr std::string_view field_type(uint32_t) {
return "uint"; }
601 static constexpr std::string_view field_type(
const uint32_t (&)[2]) {
return "uvec2"; }
602 static constexpr std::string_view field_type(
const uint32_t (&)[3]) {
return "uvec3"; }
603 static constexpr std::string_view field_type(
const uint32_t (&)[4]) {
return "uvec4"; }
605 static constexpr std::string_view field_type(uint32_t*) {
return "uint"; }
606 static constexpr std::string_view field_type(vec<uint32_t, 2>*) {
return "uvec2"; }
607 static constexpr std::string_view field_type(vec<uint32_t, 3>*) {
return "uvec3"; }
608 static constexpr std::string_view field_type(vec<uint32_t, 4>*) {
return "uvec4"; }
610 static constexpr std::string_view field_type(avnd::xy_value
auto) {
return "vec2"; }
612 static constexpr bool field_array(
float) {
return false; }
613 static constexpr bool field_array(
const float (&)[2]) {
return false; }
614 static constexpr bool field_array(
const float (&)[3]) {
return false; }
615 static constexpr bool field_array(
const float (&)[4]) {
return false; }
617 static constexpr bool field_array(
float*) {
return true; }
618 static constexpr bool field_array(vec<float, 2>*) {
return true; }
619 static constexpr bool field_array(vec<float, 3>*) {
return true; }
620 static constexpr bool field_array(vec<float, 4>*) {
return true; }
622 static constexpr bool field_array(
int) {
return false; }
623 static constexpr bool field_array(
const int (&)[2]) {
return false; }
624 static constexpr bool field_array(
const int (&)[3]) {
return false; }
625 static constexpr bool field_array(
const int (&)[4]) {
return false; }
627 static constexpr bool field_array(
int*) {
return true; }
628 static constexpr bool field_array(vec<int, 2>*) {
return true; }
629 static constexpr bool field_array(vec<int, 3>*) {
return true; }
630 static constexpr bool field_array(vec<int, 4>*) {
return true; }
632 static constexpr bool field_array(uint32_t) {
return false; }
633 static constexpr bool field_array(
const uint32_t (&)[2]) {
return false; }
634 static constexpr bool field_array(
const uint32_t (&)[3]) {
return false; }
635 static constexpr bool field_array(
const uint32_t (&)[4]) {
return false; }
637 static constexpr bool field_array(uint32_t*) {
return true; }
638 static constexpr bool field_array(vec<uint32_t, 2>*) {
return true; }
639 static constexpr bool field_array(vec<uint32_t, 3>*) {
return true; }
640 static constexpr bool field_array(vec<uint32_t, 4>*) {
return true; }
642 static constexpr bool field_array(avnd::xy_value
auto) {
return false; }
644 template <
typename T>
645 static constexpr std::string_view image_qualifier()
647 if constexpr(
requires { T::readonly; })
649 else if constexpr(
requires { T::writeonly; })
652 static_assert(T::readonly || T::writeonly);
659 template <
typename T>
660 void operator()(
const T& field)
662 shader += fmt::format(
663 "layout(location = {}) in {} {};\n", T::location(), field_type(field.data),
672 template <
typename T>
673 void operator()(
const T& field)
675 if constexpr(
requires { field.location(); })
677 shader += fmt::format(
678 "layout(location = {}) out {} {};\n", T::location(), field_type(field.data),
688 template <
typename T>
689 void operator()(
const T& field)
691 shader += fmt::format(
692 " {} {}{};\n", field_type(field.value), T::name(),
693 field_array(field.value) ?
"[]" :
"");
697 struct write_bindings
701 template <
typename C>
702 void operator()(
const C& field)
704 if constexpr(
requires { C::sampler2D; })
706 shader += fmt::format(
707 "layout(binding = {}) uniform sampler2D {};\n\n", C::binding(), C::name());
709 else if constexpr(
requires { C::image2D; })
711 shader += fmt::format(
712 "layout(binding = {}, {}) {} uniform image2D {};\n\n", C::binding(),
713 C::format(), image_qualifier<C>(), C::name());
715 else if constexpr(
requires { C::ubo; })
717 shader += fmt::format(
718 "layout({}, binding = {}) uniform {}\n{{\n",
721 C::binding(), C::name());
723 boost::pfr::for_each_field(field, write_binding{shader});
725 shader += fmt::format(
"}};\n\n");
727 else if constexpr(
requires { C::buffer; })
729 shader += fmt::format(
730 "layout({}, binding = {}) buffer {}\n{{\n",
733 C::binding(), C::name());
735 boost::pfr::for_each_field(field, write_binding{shader});
737 shader += fmt::format(
"}};\n\n");
742 template <
typename T>
743 std::string vertex_shader(
const T& lay)
745 using namespace gpp::qrhi;
746 std::string shader =
"#version 450\n\n";
748 if constexpr(
requires { lay.vertex_input; })
749 boost::pfr::for_each_field(lay.vertex_input, write_input{shader});
750 else if constexpr(
requires {
typename T::vertex_input; })
751 boost::pfr::for_each_field(
typename T::vertex_input{}, write_input{shader});
753 boost::pfr::for_each_field(
754 DefaultPipeline::layout::vertex_input{}, write_input{shader});
756 if constexpr(
requires { lay.vertex_output; })
757 boost::pfr::for_each_field(lay.vertex_output, write_output{shader});
758 else if constexpr(
requires {
typename T::vertex_output; })
759 boost::pfr::for_each_field(
typename T::vertex_output{}, write_output{shader});
763 if constexpr(
requires { lay.bindings; })
764 boost::pfr::for_each_field(lay.bindings, write_bindings{shader});
765 else if constexpr(
requires {
typename T::bindings; })
766 boost::pfr::for_each_field(
typename T::bindings{}, write_bindings{shader});
771 template <
typename T>
772 std::string fragment_shader(
const T& lay)
774 std::string shader =
"#version 450\n\n";
776 if constexpr(
requires { lay.fragment_input; })
777 boost::pfr::for_each_field(lay.fragment_input, write_input{shader});
778 else if constexpr(
requires {
typename T::fragment_input; })
779 boost::pfr::for_each_field(
typename T::fragment_input{}, write_input{shader});
781 if constexpr(
requires { lay.fragment_output; })
782 boost::pfr::for_each_field(lay.fragment_output, write_output{shader});
783 else if constexpr(
requires {
typename T::fragment_output; })
784 boost::pfr::for_each_field(
typename T::fragment_output{}, write_output{shader});
788 if constexpr(
requires { lay.bindings; })
789 boost::pfr::for_each_field(lay.bindings, write_bindings{shader});
790 else if constexpr(
requires {
typename T::bindings; })
791 boost::pfr::for_each_field(
typename T::bindings{}, write_bindings{shader});
796 template <
typename T>
797 std::string compute_shader(
const T& lay)
799 std::string fstr =
"#version 450\n\n";
802 if constexpr(
requires { T::local_size_x(); })
804 fstr += fmt::format(
"local_size_x = {}, ", T::local_size_x());
806 if constexpr(
requires { T::local_size_y(); })
808 fstr += fmt::format(
"local_size_y = {}, ", T::local_size_y());
810 if constexpr(
requires { T::local_size_z(); })
812 fstr += fmt::format(
"local_size_z = {}, ", T::local_size_z());
816 fstr.resize(fstr.size() - 2);
819 boost::pfr::for_each_field(lay.bindings, write_bindings{fstr});
830 template <
typename T>
831 void initWorker(
this auto& self, T& state)
noexcept
833 if constexpr(avnd::has_worker<T>)
835 auto ptr = QPointer{&self};
836 auto& tq = score::TaskPool::instance();
837 using worker_type =
decltype(state.worker);
839 state.worker.request = [ptr, &tq, &state]<
typename... Args>(Args&&... f) {
840 using type_of_result =
decltype(worker_type::work(std::forward<Args>(f)...));
841 tq.post([... ff = std::forward<Args>(f), &state, ptr]()
mutable {
842 if constexpr(std::is_void_v<type_of_result>)
844 worker_type::work(std::forward<
decltype(ff)>(ff)...);
850 auto res = worker_type::work(std::forward<
decltype(ff)>(ff)...);
854 ossia::qt::run_async(
855 QCoreApplication::instance(),
856 [res = std::move(res), &state, ptr]()
mutable {
867template <
typename GpuNodeRenderer,
typename Node>
870 GpuNodeRenderer& gpu;
876 bool can_process_message(std::size_t N)
878 if(mess.input.size() <= N)
881 if(prev_mess.input.size() == mess.input.size())
883 auto& prev = prev_mess.input[N];
884 auto& next = mess.input[N];
885 if(prev.index() == 1 && next.index() == 1)
887 if(ossia::get<ossia::value>(prev) == ossia::get<ossia::value>(next))
896 void operator()(avnd::parameter
auto& t,
auto field_index)
898 if(!can_process_message(field_index))
901 if(
auto val = ossia::get_if<ossia::value>(&mess.input[field_index]))
903 oscr::from_ossia_value(t, *val, t.value);
904 if_possible(t.update(state));
908#if OSCR_HAS_MMAP_FILE_STORAGE
909 template <avnd::raw_file_port Field, std::
size_t NField>
910 void operator()(Field& t, avnd::field_index<NField> field_index)
913 using node_type = std::remove_cvref_t<
decltype(gpu.node())>;
914 using file_ports = avnd::raw_file_input_introspection<Node>;
916 if(!can_process_message(field_index))
919 auto val = ossia::get_if<ossia::value>(&mess.input[field_index]);
923 static constexpr bool has_text =
requires {
decltype(Field::file)::text; };
924 static constexpr bool has_mmap =
requires {
decltype(Field::file)::mmap; };
927 if(
auto hdl = loadRawfile(*val, ctx, has_text, has_mmap))
929 static constexpr auto N = file_ports::field_index_to_index(NField);
930 if constexpr(avnd::port_can_process<Field>)
934 auto func = executePortPreprocess<Field>(*hdl);
935 const_cast<node_type&
>(gpu.node())
937 state, hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
943 const_cast<node_type&
>(gpu.node())
945 state, hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
951 template <avnd::texture_port Field, std::
size_t NField>
952 void operator()(Field& t, avnd::field_index<NField> field_index)
954 using node_type = std::remove_cvref_t<
decltype(gpu.node())>;
955 auto& node =
const_cast<node_type&
>(gpu.node());
956 auto val = ossia::get_if<ossia::render_target_spec>(&mess.input[field_index]);
959 node.process(NField, *val);
962 void operator()(
auto& t,
auto field_index) =
delete;
967 template <
typename Self,
typename Node_T>
968 static void processControlIn(
973 avnd::input_introspection<Node_T>::for_all_n(
974 avnd::get_inputs<Node_T>(state),
975 GpuProcessIns<Self, Node_T>{self, state, renderer_mess, mess, ctx});
976 renderer_mess = mess;
982 std::weak_ptr<Execution::ExecutionCommandQueue> queue;
983 Gfx::exec_controls control_outs;
987 template <
typename Node_T>
988 void processControlOut(Node_T& state)
const noexcept
990 if(!this->control_outs.empty())
992 auto q = this->queue.lock();
997 avnd::parameter_output_introspection<Node_T>::for_all(
998 avnd::get_outputs(state), [&]<avnd::parameter T>(
const T& t) {
999 qq.enqueue([v = oscr::to_ossia_value(t, t.value),
1000 port = control_outs[parm_k]]()
mutable {
1001 std::swap(port->value, v);
1002 port->changed = true;
1011template <
typename T>
1012struct SCORE_PLUGIN_AVND_EXPORT GpuNodeElements
1014 [[no_unique_address]] oscr::soundfile_storage<T> soundfiles;
1016 [[no_unique_address]] oscr::midifile_storage<T> midifiles;
1018#if defined(OSCR_HAS_MMAP_FILE_STORAGE)
1019 [[no_unique_address]] oscr::raw_file_storage<T> rawfiles;
1022 template <std::
size_t N, std::
size_t NField>
1024 auto& state,
const std::shared_ptr<oscr::raw_file_data>& hdl,
1025 avnd::predicate_index<N>, avnd::field_index<NField>)
1027 this->rawfiles.load(
1028 state, hdl, avnd::predicate_index<N>{}, avnd::field_index<NField>{});
1035 :
score::gfx::NodeModel{}
1039 virtual ~CustomGfxNodeBase();
1047 virtual ~CustomGfxOutputNodeBase();
1052struct CustomGpuNodeBase
1059 std::weak_ptr<Execution::ExecutionCommandQueue>&& q, Gfx::exec_controls&& ctls,
1061 : GpuControlOuts{
std::move(q),
std::move(ctls)}
1066 virtual ~CustomGpuNodeBase() =
default;
1069 QString vertex, fragment, compute;
1074struct SCORE_PLUGIN_AVND_EXPORT CustomGpuOutputNodeBase
1080 CustomGpuOutputNodeBase(
1081 std::weak_ptr<Execution::ExecutionCommandQueue> q, Gfx::exec_controls&& ctls,
1083 virtual ~CustomGpuOutputNodeBase();
1086 std::weak_ptr<score::gfx::RenderList> m_renderer{};
1087 std::shared_ptr<score::gfx::RenderState> m_renderState{};
1088 std::function<void()> m_update;
1090 QString vertex, fragment, compute;
1095 void setRenderer(std::shared_ptr<score::gfx::RenderList>)
override;
1098 void startRendering()
override;
1099 void render()
override;
1100 void stopRendering()
override;
1101 bool canRender()
const override;
1102 void onRendererChange()
override;
1106 std::function<
void()> onUpdate, std::function<
void()> onResize)
override;
1108 void destroyOutput()
override;
1109 std::shared_ptr<score::gfx::RenderState> renderState()
const override;
1111 Configuration configuration() const noexcept override;
1114template <typename Node_T, typename Node>
1115void prepareNewState(Node_T& eff, const Node& parent)
1117 if constexpr(avnd::has_worker<Node_T>)
1119 parent.initWorker(eff);
1121 if constexpr(avnd::has_processor_to_gui_bus<Node_T>)
1123 auto& process = parent.processModel;
1124 eff.send_message = [&process](
auto&& b)
mutable {
1129 MessageBusSender{process.to_ui}(std::move(b));
1136 avnd::init_controls(eff);
1138 if constexpr(avnd::can_prepare<Node_T>)
1140 if constexpr(avnd::function_reflection<&Node_T::prepare>::count == 1)
1142 using prepare_type = avnd::first_argument<&Node_T::prepare>;
1144 if_possible(t.instance = parent.instance);
1154struct port_to_type_enum
1156 template <std::
size_t I, avnd::cpu_texture_port F>
1157 constexpr auto operator()(avnd::field_reflection<I, F> p)
1159 using texture_type = std::remove_cvref_t<
decltype(F::texture)>;
1160 return avnd::cpu_fixed_format_texture<texture_type> ? score::gfx::Types::Image
1161 : score::gfx::Types::Buffer;
1163 template <std::
size_t I, avnd::sampler_port F>
1164 constexpr auto operator()(avnd::field_reflection<I, F> p)
1166 return score::gfx::Types::Image;
1168 template <std::
size_t I, avnd::image_port F>
1169 constexpr auto operator()(avnd::field_reflection<I, F> p)
1171 return score::gfx::Types::Image;
1173 template <std::
size_t I, avnd::attachment_port F>
1174 constexpr auto operator()(avnd::field_reflection<I, F> p)
1176 return score::gfx::Types::Image;
1179 template <std::
size_t I, avnd::geometry_port F>
1180 constexpr auto operator()(avnd::field_reflection<I, F> p)
1182 return score::gfx::Types::Geometry;
1184 template <std::
size_t I, avnd::mono_audio_port F>
1185 constexpr auto operator()(avnd::field_reflection<I, F> p)
1187 return score::gfx::Types::Audio;
1189 template <std::
size_t I, avnd::poly_audio_port F>
1190 constexpr auto operator()(avnd::field_reflection<I, F> p)
1192 return score::gfx::Types::Audio;
1194 template <std::
size_t I, avnd::
int_parameter F>
1195 constexpr auto operator()(avnd::field_reflection<I, F> p)
1197 return score::gfx::Types::Int;
1199 template <std::
size_t I, avnd::enum_parameter F>
1200 constexpr auto operator()(avnd::field_reflection<I, F> p)
1202 return score::gfx::Types::Int;
1204 template <std::
size_t I, avnd::
float_parameter F>
1205 constexpr auto operator()(avnd::field_reflection<I, F> p)
1207 return score::gfx::Types::Float;
1209 template <std::
size_t I, avnd::parameter F>
1210 constexpr auto operator()(avnd::field_reflection<I, F> p)
1212 using value_type = std::remove_cvref_t<
decltype(F::value)>;
1214 if constexpr(std::is_aggregate_v<value_type>)
1216 constexpr int sz = boost::pfr::tuple_size_v<value_type>;
1217 if constexpr(sz == 2)
1219 return score::gfx::Types::Vec2;
1221 else if constexpr(sz == 3)
1223 return score::gfx::Types::Vec3;
1225 else if constexpr(sz == 4)
1227 return score::gfx::Types::Vec4;
1230 return score::gfx::Types::Empty;
1232 template <std::
size_t I,
typename F>
1233 constexpr auto operator()(avnd::field_reflection<I, F> p)
1235 return score::gfx::Types::Empty;
1239template <
typename Node_T>
1240inline void initGfxPorts(
auto* self,
auto& input,
auto& output)
1242 avnd::input_introspection<Node_T>::for_all(
1243 [self, &input]<
typename Field, std::size_t I>(avnd::field_reflection<I, Field> f) {
1244 static constexpr auto type = port_to_type_enum{}(f);
1247 avnd::output_introspection<Node_T>::for_all(
1249 &output]<
typename Field, std::size_t I>(avnd::field_reflection<I, Field> f) {
1250 static constexpr auto type = port_to_type_enum{}(f);
1256inplaceMirror(
unsigned char* bytes,
int width,
int height,
int bytes_per_pixel)
1258 if(width < 1 || height <= 1)
1260 const size_t row_size = width * bytes_per_pixel;
1262 auto temp_row = (
unsigned char*)alloca(row_size);
1264 auto bottom = bytes + (height - 1) * row_size;
1268 memcpy(temp_row, top, row_size);
1269 memcpy(top, bottom, row_size);
1270 memcpy(bottom, temp_row, row_size);
Root data model for visual nodes.
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:75
virtual void process(Message &&msg)
Process a message from the execution engine.
Definition Node.cpp:25
Common base class for most single-pass, simple nodes.
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:230
Base class for sink nodes (QWindow, spout, syphon, NDI output, ...)
Definition OutputNode.hpp:24
List of nodes to be rendered to an output.
Definition RenderList.hpp:19
TreeNode< DeviceExplorerNode > Node
Definition DeviceNode.hpp:74
Definition Factories.hpp:19
GraphicsApi
Available graphics APIs to use.
Definition RenderState.hpp:20
Base toolkit upon which the software is built.
Definition Application.cpp:97
Definition DocumentContext.hpp:18
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:50
Port of a score::gfx::Node.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:48