Loading...
Searching...
No Matches
RenderedCSFNode.hpp
1#pragma once
2#include <Gfx/Graph/GPUBufferScatter.hpp>
3#include <Gfx/Graph/ISFNode.hpp>
4#include <Gfx/Graph/NodeRenderer.hpp>
5
6#include <ossia/detail/small_flat_map.hpp>
7#include <ossia/detail/small_vector.hpp>
8
9namespace ossia { class math_expression; }
10
11namespace score::gfx
12{
13
15{
16 explicit RenderedCSFNode(const ISFNode& node) noexcept;
17
18 virtual ~RenderedCSFNode();
19
20 void updateInputTexture(const Port& input, QRhiTexture* tex) override;
21 QRhiTexture* textureForOutput(const Port& output) override;
22
23 void init(RenderList& renderer, QRhiResourceUpdateBatch& res) override;
24 void update(RenderList& renderer, QRhiResourceUpdateBatch& res, Edge* edge) override;
25 void release(RenderList& r) override;
26
27 void runInitialPasses(
28 RenderList&, QRhiCommandBuffer& commands, QRhiResourceUpdateBatch*& res,
29 Edge& edge) override;
30
31 void runRenderPass(RenderList&, QRhiCommandBuffer& commands, Edge& edge) override;
32
33private:
34 void initComputePass(const TextureRenderTarget& rt, RenderList& renderer, Edge& edge, QRhiResourceUpdateBatch& res);
35 void createComputePipeline(RenderList& renderer);
36 void createGraphicsPass(const TextureRenderTarget& rt, RenderList& renderer, Edge& edge, QRhiResourceUpdateBatch& res);
37 void updateDescriptorSet(RenderList& renderer, Edge& edge);
38 std::vector<Sampler> allSamplers() const noexcept;
39
40 // Expression evaluation helper
41 void registerCommonExpressionVariables(
42 ossia::math_expression& e, ossia::small_pod_vector<double, 16>& data) const;
43
44 // Image management
45 std::optional<QSize> getImageSize(const isf::csf_image_input&) const noexcept;
46 QSize computeTextureSize(const isf::csf_image_input& img) const noexcept;
47
48 // Buffer management methods
49 int calculateStorageBufferSize(std::span<const isf::storage_input::layout_field> layout, int arrayCount) const;
50 BufferView createStorageBuffer(
51 RenderList& renderer, const QString& name, const QString& access, int size);
52 void updateStorageBuffers(RenderList& renderer, QRhiResourceUpdateBatch& res);
53 void recreateShaderResourceBindings(RenderList& renderer, QRhiResourceUpdateBatch& res);
54 int getArraySizeFromUI(const QString& bufferName) const;
55 QString updateShaderWithImageFormats(QString current);
56
57 // Geometry buffer management
58 void updateGeometryBindings(RenderList& renderer, QRhiResourceUpdateBatch& res);
59 void pushOutputGeometry(RenderList& renderer, QRhiResourceUpdateBatch& res, Edge& edge);
60 int resolveCountExpression(
61 const std::string& expr, const isf::geometry_input& geo,
62 const std::string& fieldName) const;
63 int resolveDispatchExpression(const std::string& expr) const;
64
65 BufferView bufferForOutput(const score::gfx::Port& output) override;
66
67 struct ComputePass
68 {
69 QRhiComputePipeline* pipeline{};
70 QRhiShaderResourceBindings* srb{};
71 QRhiBuffer* processUBO{};
72 };
73
74 struct GraphicsPass
75 {
76 Pipeline pipeline;
77 QRhiSampler* outputSampler{};
78 MeshBuffers meshBuffers;
79 };
80
81 ossia::small_vector<std::pair<Edge*, ComputePass>, 2> m_computePasses;
82 ossia::small_vector<std::pair<Edge*, GraphicsPass>, 2> m_graphicsPasses;
83
84 ISFNode& n;
85
86 std::vector<Sampler> m_inputSamplers;
87
88 // Storage buffers for compute shaders
89 struct StorageBuffer
90 {
91 QRhiBuffer* buffer{};
92 int64_t size{};
93 int64_t lastKnownSize{}; // For dynamic resizing
94 QString name;
95 QString access; // "read_only", "write_only", "read_write"
96 std::vector<isf::storage_input::layout_field> layout; // For size calculation
97 bool owned{true}; // false when buffer comes from geometry auxiliary
98 std::string buffer_usage; // "", "indirect_draw", "indirect_draw_indexed"
99 };
100 std::vector<StorageBuffer> m_storageBuffers; // Contains both ins and outs
101
102 // Only outs, matched with index in m_storageBuffers
103 std::vector<std::pair<const score::gfx::Port*, int>> m_outStorageBuffers;
104
105 // Storage images for compute shaders
106 struct StorageImage
107 {
108 QRhiTexture* texture{};
109 QString name;
110 QString access; // "read_only", "write_only", "read_write"
111 QRhiTexture::Format format{QRhiTexture::RGBA8};
112 };
113 std::vector<StorageImage> m_storageImages;
114
115 // Only outs, matched with index in m_storageImages
116 std::vector<std::pair<const score::gfx::Port*, int>> m_outStorageImages;
117
118 // Geometry input bindings: SoA SSBOs created from incoming ossia::geometry
119 struct GeometryBinding
120 {
121 // One SSBO per declared attribute in the geometry_input
123 {
124 QRhiBuffer* buffer{}; // GPU SSBO for this attribute (write target / primary)
125 QRhiBuffer* read_buffer{}; // Separate read buffer for ping-pong (nullptr = use buffer for both)
126 int64_t size{}; // Current buffer size in bytes
127 bool owned{true}; // true = we created it; false = referencing upstream gpu_buffer
128 std::string name; // e.g. "position", "velocity"
129 std::string access; // "read_only", "write_only", "read_write"
130 bool per_instance{false}; // true = sized by instance_count, false = sized by vertex_count
131 const void* lastUploadSrc{};// CPU data pointer from last upload (for dedup)
132
133 // GPU scatter state (used when format conversion is needed)
134 QRhiBuffer* scatterStaging{}; // Staging SSBO for raw CPU data
135 int64_t scatterStagingSize{};
137 GPUBufferScatter::Params scatterParams;
138 bool scatterPending{false}; // true = needs dispatch this frame
139 };
140
141 // Structured SSBOs that travel with the geometry (matched by name
142 // against ossia::geometry::auxiliary_buffer entries).
144 {
145 QRhiBuffer* buffer{}; // GPU SSBO (write target / primary)
146 QRhiBuffer* read_buffer{}; // Separate read buffer for ping-pong (nullptr = use buffer for both)
147 int64_t size{};
148 bool owned{true};
149 std::string name;
150 std::string access;
151 std::vector<isf::storage_input::layout_field> layout;
152 std::string size_expr; // expression for flexible array count, may contain $USER
153 };
154
155 std::vector<AttributeSSBO> attribute_ssbos;
156 std::vector<AuxiliarySSBO> auxiliary_ssbos;
157 int vertex_count{0}; // Number of elements (vertices) in the geometry
158 int instance_count{1}; // Number of instances
159 int input_port_index{-1}; // Input port index for this binding (-1 = no input port, e.g. write_only generator)
160 bool has_output{false}; // true if any attribute is writable
161 bool has_vertex_count_spec{false}; // true if vertex_count expression is set
162 bool has_instance_count_spec{false}; // true if instance_count expression is set
163 bool is_feedback_receiver{false}; // true = uses ping-pong double buffering for read_write attrs
164 bool pending_initial_copy{false}; // first frame after read_buffer allocated: use same-buffer mode, then copy buffer→read_buffer
165
166 // GPU buffers allocated by COPY_FROM (CPU→GPU upload). Owned by this binding,
167 // must be released via renderer.releaseBuffer() since they escape into output geometry.
168 std::vector<QRhiBuffer*> copyFromBuffers;
169
170 // Persistent output geometry — reused across frames to avoid per-frame shared_ptr allocation.
171 // Updated in-place; dirty_index incremented when structure or handles change.
172 ossia::geometry_spec outputGeometry;
173 int prev_vertex_count{-1}; // Track structural changes
174 int prev_instance_count{-1};
175 int prev_attribute_count{-1};
176 int prev_upstream_attr_count{-1};
177
178#if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0)
179 QRhiBuffer* indirectDrawBuffer{}; // StorageBuffer | IndirectBuffer for GPU-driven draw args
180 bool uses_indirect_draw{false}; // true when geometry_input has INDIRECT_DRAW: true
181 bool indirect_draw_indexed{false}; // true for drawIndexedIndirect, false for drawIndirect
182#endif
183 };
184 std::vector<GeometryBinding> m_geometryBindings;
185
186 QRhiBuffer* m_materialUBO{};
187 int m_materialSize{};
188
189 // Output texture for compute shader results
190 QRhiTexture* m_outputTexture{};
191 QRhiTexture::Format m_outputFormat{QRhiTexture::RGBA8};
192
193 // Compute shader specifics
194 QRhiComputePipeline* m_computePipeline{}; // Points to first pass pipeline (backward compat)
195 QShader m_computeShader;
196 QString m_computeShaderSource; // Template with ISF_LOCAL_SIZE_X/Y/Z placeholders
197 std::vector<QRhiComputePipeline*> m_perPassPipelines; // One entry per pass (may share pipelines)
198 std::vector<QRhiComputePipeline*> m_ownedPipelines; // Unique pipelines for cleanup
199 bool m_pipelinesDirty{true};
200
201 // GPU buffer scatter (format conversion on GPU)
202 GPUBufferScatter m_gpuScatter;
203 bool m_gpuScatterAvailable{false};
204
205 // True once at least one frame's worth of upstream rendering has happened
206 // for this renderer's input textures. Used to gate generateMips() so we
207 // don't trip a Vulkan validation error on freshly-allocated textures whose
208 // layout is still PREINITIALIZED. Reset on init() / after release() so a
209 // RenderList rebuild starts the cycle over.
210 bool m_inputsHaveBeenWritten{false};
211};
212
213}
Data model for Interactive Shader Format filters.
Definition ISFNode.hpp:20
Renderer for a given node.
Definition NodeRenderer.hpp:11
List of nodes to be rendered to an output.
Definition RenderList.hpp:19
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
Definition Mesh.hpp:15
Connection between two score::gfx::Port.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:75
Definition GPUBufferScatter.hpp:30
Create or update an SRB+UBO for a specific scatter operation.
Definition GPUBufferScatter.hpp:45
Definition Mesh.hpp:33
Useful abstraction for storing a graphics pipeline and associated resource bindings.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:104
Port of a score::gfx::Node.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:54
Definition RenderedCSFNode.hpp:15
void updateInputTexture(const Port &input, QRhiTexture *tex) override
Definition RenderedCSFNode.cpp:143
QRhiTexture * textureForOutput(const Port &output) override
Definition RenderedCSFNode.cpp:170
Useful abstraction for storing all the data related to a render target.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:122