4#include <Crousti/GfxNode.hpp>
9template <
typename Node_T>
11 avnd::texture_input_introspection<Node_T>::size > 0
12 && avnd::texture_output_introspection<Node_T>::size > 0)
13struct 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>;
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 const GfxNode<Node_T>& node() const noexcept
27 return static_cast<const GfxNode<Node_T>&
>(score::gfx::NodeRenderer::node);
30 GfxRenderer(
const GfxNode<Node_T>& p)
31 :
score::gfx::GenericNodeRenderer{p}
32 , m_readbacks(texture_inputs::size)
34 prepareNewState(state, p);
40 auto it = m_rts.find(&p);
41 SCORE_ASSERT(it != m_rts.end());
45 template <
typename Tex>
50 auto& parent = node();
51 auto port = parent.input[k];
52 static constexpr auto flags
53 = QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource;
54 auto texture = renderer.
state.rhi->newTexture(
55 gpp::qrhi::textureFormat<Tex>(), spec.size, 1, flags);
56 SCORE_ASSERT(texture->create());
61 template <
typename Tex>
65 auto& rhi = *renderer.
state.rhi;
67 if(size.width() > 0 && size.height() > 0)
69 texture = rhi.newTexture(
70 gpp::qrhi::textureFormat<Tex>(), size, 1, QRhiTexture::Flag{});
75 auto sampler = rhi.newSampler(
76 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
77 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
80 this->m_samplers.push_back({sampler, texture});
83 template <avnd::cpu_texture Tex>
86 auto& [sampler, texture] = this->m_samplers[k];
89 auto sz = texture->pixelSize();
90 if(cpu_tex.width == sz.width() && cpu_tex.height == sz.height())
95 if(cpu_tex.width > 0 && cpu_tex.height > 0)
97 QRhiTexture* oldtex = texture;
98 QRhiTexture* newtex = renderer.
state.rhi->newTexture(
99 gpp::qrhi::textureFormat<Tex>(), QSize{cpu_tex.width, cpu_tex.height}, 1,
100 QRhiTexture::Flag{});
102 for(
auto& [edge, pass] : this->m_p)
104 score::gfx::replaceTexture(*pass.srb, sampler, newtex);
109 oldtex->deleteLater();
116 for(
auto& [edge, pass] : this->m_p)
118 score::gfx::replaceTexture(*pass.srb, sampler, &renderer.emptyTexture());
124 void uploadOutputTexture(
126 QRhiResourceUpdateBatch* res)
130 if(
auto texture = updateTexture(renderer, k, cpu_tex))
134 QRhiTextureSubresourceUploadDescription sd(cpu_tex.bytes, cpu_tex.bytesize());
135 QRhiTextureUploadDescription desc{QRhiTextureUploadEntry{0, 0, sd}};
136 res->uploadTexture(texture, desc);
139 cpu_tex.changed =
false;
145 void loadInputTexture(QRhi& rhi, avnd::cpu_texture
auto& cpu_tex,
int k)
147 auto& buf = m_readbacks[k].data;
148 if(buf.size() != (qsizetype)cpu_tex.bytesize())
150 cpu_tex.bytes =
nullptr;
154 cpu_tex.bytes =
reinterpret_cast<unsigned char*
>(buf.data());
157 if(cpu_tex.width * cpu_tex.height > 0)
159 cpu_tex.bytes, cpu_tex.width, cpu_tex.height, cpu_tex.bytes_per_pixel);
161 cpu_tex.changed =
true;
167 auto& parent = node();
168 if constexpr(
requires { state.prepare(); })
170 parent.processControlIn(
171 *
this, state, m_last_message, parent.last_message, parent.m_ctx);
176 this->defaultMeshInit(renderer, mesh, res);
177 this->processUBOInit(renderer);
181 std::tie(this->m_vertexS, this->m_fragmentS)
187 avnd::cpu_texture_input_introspection<Node_T>::for_all(
188 avnd::get_inputs<Node_T>(state), [&]<
typename F>(F& t) {
190 auto spec = this->node().resolveRenderTargetSpecs(k, renderer);
191 if constexpr(
requires {
196 spec.size.rwidth() = t.request_width;
197 spec.size.rheight() = t.request_height;
199 createInput(renderer, k, t.texture, spec);
200 if constexpr(avnd::cpu_fixed_format_texture<
decltype(t.texture)>)
202 t.texture.width = spec.size.width();
203 t.texture.height = spec.size.height();
211 avnd::cpu_texture_output_introspection<Node_T>::for_all(
212 avnd::get_outputs<Node_T>(state), [&](
auto& t) {
213 createOutput(renderer, t.texture, QSize{t.texture.width, t.texture.height});
217 this->defaultPassesInit(renderer, mesh);
224 this->defaultUBOUpdate(renderer, res);
230 for(
auto& [sampl, texture] : this->m_samplers)
233 texture->deleteLater();
239 for(
auto [port, rt] : m_rts)
243 this->defaultRelease(r);
246 void inputAboutToFinish(
248 QRhiResourceUpdateBatch*& res)
override
250 auto& parent = node();
251 res = renderer.
state.rhi->nextResourceUpdateBatch();
252 const auto& inputs = parent.input;
253 auto index_of_port = ossia::find(inputs, &p) - inputs.begin();
255 auto tex = m_rts[&p].texture;
256 auto& readback = m_readbacks[index_of_port];
258 res->readBackTexture(QRhiReadbackDescription{tex}, &readback);
262 void runInitialPasses(
266 auto& parent = node();
267 auto& rhi = *renderer.
state.rhi;
273 if(parent.last_message.token.date == m_last_time)
276 m_last_time = parent.last_message.token.date;
284 avnd::cpu_texture_input_introspection<Node_T>::for_all(
285 avnd::get_inputs<Node_T>(state), [&](
auto& t) {
286 loadInputTexture(rhi, t.texture, k);
291 parent.processControlIn(
292 *
this, state, m_last_message, parent.last_message, parent.m_ctx);
300 avnd::cpu_texture_output_introspection<Node_T>::for_all(
301 avnd::get_outputs<Node_T>(state), [&](
auto& t) {
302 uploadOutputTexture(renderer, k, t.texture, res);
306 commands.resourceUpdate(res);
307 res = renderer.
state.rhi->nextResourceUpdateBatch();
311 parent.processControlOut(this->state);
315template <
typename Node_T>
316 requires(avnd::texture_input_introspection<Node_T>::size > 0
317 && avnd::texture_output_introspection<Node_T>::size > 0)
318struct GfxNode<Node_T>
final
323 , GpuNodeElements<Node_T>
328 std::weak_ptr<Execution::ExecutionCommandQueue> q, Gfx::exec_controls ctls,
int id,
330 : CustomGfxNodeBase{ctx}
331 , GpuControlOuts{
std::move(q),
std::move(ctls)}
332 , processModel{element}
336 initGfxPorts<Node_T>(
this, this->input, this->output);
342 return new GfxRenderer<Node_T>{*
this};
Definition score-plugin-avnd/Crousti/ProcessModel.hpp:79
Renderer for a given node.
Definition NodeRenderer.hpp:11
List of nodes to be rendered to an output.
Definition RenderList.hpp:19
bool requiresDepth() const noexcept
Whether this list of rendering actions requires depth testing at all.
Definition RenderList.hpp:137
const score::gfx::Mesh & defaultTriangle() const noexcept
A triangle mesh correct for this API.
Definition RenderList.cpp:305
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:112
Definition Factories.hpp:19
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:390
TextureRenderTarget createRenderTarget(const RenderState &state, QRhiTexture *tex, int samples, bool depth)
Create a render target from a texture.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:10
Base toolkit upon which the software is built.
Definition Application.cpp:97
Definition DocumentContext.hpp:18
Connection between two score::gfx::Port.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:66
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:50
Port of a score::gfx::Node.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:48
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:57
Useful abstraction for storing all the data related to a render target.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:111