4 #include <Crousti/GfxNode.hpp>
9 template <
typename Node_T>
11 avnd::texture_input_introspection<Node_T>::size > 0
12 && avnd::texture_output_introspection<Node_T>::size > 0)
13 struct GfxRenderer<Node_T> final :
score::gfx::GenericNodeRenderer
15 using texture_inputs = avnd::texture_input_introspection<Node_T>;
16 using texture_outputs = avnd::texture_output_introspection<Node_T>;
17 const GfxNode<Node_T>& parent;
19 ossia::small_flat_map<const score::gfx::Port*, score::gfx::TextureRenderTarget, 2>
22 std::vector<QRhiReadbackResult> m_readbacks;
23 ossia::time_value m_last_time{-1};
25 GfxRenderer(
const GfxNode<Node_T>& p)
26 :
score::gfx::GenericNodeRenderer{p}
28 , m_readbacks(texture_inputs::size)
30 prepareNewState(state, parent);
36 auto it = m_rts.find(&p);
37 SCORE_ASSERT(it != m_rts.end());
41 template <
typename Tex>
45 auto port = parent.input[k];
46 constexpr
auto flags = QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource;
47 auto texture = renderer.
state.rhi->newTexture(
48 gpp::qrhi::textureFormat<Tex>(), size, 1, flags);
49 SCORE_ASSERT(texture->create());
54 template <
typename Tex>
58 auto& rhi = *renderer.
state.rhi;
60 if(size.width() > 0 && size.height() > 0)
62 texture = rhi.newTexture(
63 gpp::qrhi::textureFormat<Tex>(), size, 1, QRhiTexture::Flag{});
68 auto sampler = rhi.newSampler(
69 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
70 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
73 this->m_samplers.push_back({sampler, texture});
76 template <avnd::cpu_texture Tex>
79 auto& [sampler, texture] = this->m_samplers[k];
82 auto sz = texture->pixelSize();
83 if(cpu_tex.width == sz.width() && cpu_tex.height == sz.height())
88 if(cpu_tex.width > 0 && cpu_tex.height > 0)
90 QRhiTexture* oldtex = texture;
91 QRhiTexture* newtex = renderer.
state.rhi->newTexture(
92 gpp::qrhi::textureFormat<Tex>(), QSize{cpu_tex.width, cpu_tex.height}, 1,
95 for(
auto& [edge, pass] : this->m_p)
97 score::gfx::replaceTexture(*pass.srb, sampler, newtex);
102 oldtex->deleteLater();
109 for(
auto& [edge, pass] : this->m_p)
111 score::gfx::replaceTexture(*pass.srb, sampler, &renderer.
emptyTexture());
117 void uploadOutputTexture(
119 QRhiResourceUpdateBatch* res)
123 if(
auto texture = updateTexture(renderer, k, cpu_tex))
127 QRhiTextureSubresourceUploadDescription sd(
128 cpu_tex.bytes, cpu_tex.width * cpu_tex.height * 4);
129 QRhiTextureUploadDescription desc{QRhiTextureUploadEntry{0, 0, sd}};
131 res->uploadTexture(texture, desc);
134 cpu_tex.changed =
false;
140 void loadInputTexture(avnd::cpu_texture
auto& cpu_tex,
int k)
142 auto& buf = m_readbacks[k].data;
143 if(buf.size() != 4 * cpu_tex.width * cpu_tex.height)
145 cpu_tex.bytes =
nullptr;
149 cpu_tex.bytes =
reinterpret_cast<unsigned char*
>(buf.data());
150 cpu_tex.changed =
true;
156 if constexpr(requires { state.init(); })
162 this->defaultMeshInit(renderer, mesh, res);
163 this->processUBOInit(renderer);
164 this->m_material.init(renderer, this->node.input, this->m_samplers);
165 std::tie(this->m_vertexS, this->m_fragmentS)
171 avnd::cpu_texture_input_introspection<Node_T>::for_all(
172 avnd::get_inputs<Node_T>(state), [&]<
typename F>(F& t) {
173 auto sz = renderer.
state.renderSize;
174 createInput(renderer, k, t.texture, sz);
175 t.texture.width = sz.width();
176 t.texture.height = sz.height();
183 avnd::cpu_texture_output_introspection<Node_T>::for_all(
184 avnd::get_outputs<Node_T>(state), [&](
auto& t) {
185 createOutput(renderer, t.texture, QSize{t.texture.width, t.texture.height});
189 this->defaultPassesInit(renderer, mesh);
194 this->defaultUBOUpdate(renderer, res);
200 for(
auto& [sampl, texture] : this->m_samplers)
203 texture->deleteLater();
209 for(
auto [port, rt] : m_rts)
213 this->defaultRelease(r);
216 void inputAboutToFinish(
218 QRhiResourceUpdateBatch*& res)
override
220 res = renderer.
state.rhi->nextResourceUpdateBatch();
221 const auto& inputs = this->node.input;
222 auto index_of_port = ossia::find(inputs, &p) - inputs.begin();
223 SCORE_ASSERT(index_of_port == 0);
225 auto tex = m_rts[&p].texture;
226 auto& readback = m_readbacks[index_of_port];
228 res->readBackTexture(QRhiReadbackDescription{tex}, &readback);
232 void runInitialPasses(
236 auto& rhi = *renderer.
state.rhi;
239 if(parent.last_message.token.date == m_last_time)
243 m_last_time = parent.last_message.token.date;
254 avnd::cpu_texture_input_introspection<Node_T>::for_all(
255 avnd::get_inputs<Node_T>(state), [&](
auto& t) {
256 loadInputTexture(t.texture, k);
261 parent.processControlIn(state, this->parent.last_message);
269 avnd::cpu_texture_output_introspection<Node_T>::for_all(
270 avnd::get_outputs<Node_T>(state), [&](
auto& t) {
271 uploadOutputTexture(renderer, k, t.texture, res);
275 commands.resourceUpdate(res);
276 res = renderer.
state.rhi->nextResourceUpdateBatch();
280 parent.processControlOut(this->state);
284 template <
typename Node_T>
285 requires(avnd::texture_input_introspection<Node_T>::size > 0
286 && avnd::texture_output_introspection<Node_T>::size > 0)
287 struct GfxNode<Node_T> final
296 std::weak_ptr<Execution::ExecutionCommandQueue> q, Gfx::exec_controls ctls,
int id)
297 : GpuControlOuts{std::move(q), std::move(ctls)}
298 , processModel{element}
302 using texture_inputs = avnd::texture_input_introspection<Node_T>;
303 using texture_outputs = avnd::texture_output_introspection<Node_T>;
306 for(std::size_t i = 0; i < texture_inputs::size; i++)
308 this->input.push_back(
311 for(std::size_t i = 0; i < texture_outputs::size; i++)
313 this->output.push_back(
321 return new GfxRenderer<Node_T>{*
this};
Definition: score-plugin-avnd/Crousti/ProcessModel.hpp:551
Renderer for a given node.
Definition: NodeRenderer.hpp:11
List of nodes to be rendered to an output.
Definition: RenderList.hpp:19
const score::gfx::Mesh & defaultTriangle() const noexcept
A triangle mesh correct for this API.
Definition: RenderList.cpp:247
RenderState & state
RenderState corresponding to this RenderList.
Definition: RenderList.hpp:89
QRhiTexture & emptyTexture() const noexcept
Texture to use when a texture is missing.
Definition: RenderList.hpp:111
TextureRenderTarget createRenderTarget(const RenderState &state, QRhiTexture *tex, int samples)
Create a render target from a texture.
Definition: score-plugin-gfx/Gfx/Graph/Utils.cpp:10
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition: score-plugin-gfx/Gfx/Graph/Utils.cpp:334
Base toolkit upon which the software is built.
Definition: Application.cpp:90
Connection between two score::gfx::Port.
Definition: score-plugin-gfx/Gfx/Graph/Utils.hpp:64
Port of a score::gfx::Node.
Definition: score-plugin-gfx/Gfx/Graph/Utils.hpp:46
Useful abstraction for storing all the data related to a render target.
Definition: score-plugin-gfx/Gfx/Graph/Utils.hpp:109