MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GeometryBindingsProcessor.cpp
Go to the documentation of this file.
2
6
7namespace MayaFlux::Buffers {
8
14
16 const std::string& name,
17 const std::shared_ptr<Nodes::GpuSync::GeometryWriterNode>& node,
18 const std::shared_ptr<VKBuffer>& vertex_buffer)
19{
20 if (!node) {
21 error<std::invalid_argument>(
24 std::source_location::current(),
25 "Cannot bind null geometry node '{}'", name);
26 }
27
28 if (!vertex_buffer) {
29 error<std::invalid_argument>(
32 std::source_location::current(),
33 "Cannot bind geometry node '{}' to null vertex buffer", name);
34 }
35
36 size_t vertex_data_size = node->get_vertex_buffer_size_bytes();
37
38 if (vertex_buffer->get_size_bytes() < vertex_data_size) {
40 "Vertex buffer for '{}' may be too small: {} bytes required, {} available. "
41 "Will upload partial data.",
42 name, vertex_data_size, vertex_buffer->get_size_bytes());
43 }
44
45 std::shared_ptr<VKBuffer> staging = nullptr;
46 if (!vertex_buffer->is_host_visible()) {
47 size_t staging_size = std::max<size_t>(vertex_buffer->get_size_bytes(), vertex_data_size);
48 staging = create_staging_buffer(staging_size);
49
51 "Created staging buffer for device-local geometry '{}' ({} bytes)",
52 name, staging_size);
53 } else {
55 "No staging needed for host-visible geometry '{}'", name);
56 }
57
59 .node = node,
60 .gpu_vertex_buffer = vertex_buffer,
61 .staging_buffer = staging
62 };
63
65 "Bound geometry node '{}' ({} vertices, {} bytes, stride: {})",
66 name, node->get_vertex_count(), vertex_data_size, node->get_vertex_stride());
67}
68
70{
71 if (m_bindings.erase(name) == 0) {
73 "Attempted to unbind non-existent geometry node '{}'", name);
74 } else {
76 "Unbound geometry node '{}'", name);
77 }
78}
79
80bool GeometryBindingsProcessor::has_binding(const std::string& name) const
81{
82 return m_bindings.contains(name);
83}
84
85std::vector<std::string> GeometryBindingsProcessor::get_binding_names() const
86{
87 std::vector<std::string> names;
88 names.reserve(m_bindings.size());
89 for (const auto& [name, _] : m_bindings) {
90 names.push_back(name);
91 }
92 return names;
93}
94
96{
97 return m_bindings.size();
98}
99
100std::optional<GeometryBindingsProcessor::GeometryBinding>
101GeometryBindingsProcessor::get_binding(const std::string& name) const
102{
103 auto it = m_bindings.find(name);
104 if (it != m_bindings.end()) {
105 return it->second;
106 }
107 return std::nullopt;
108}
109
110void GeometryBindingsProcessor::processing_function(std::shared_ptr<Buffer> buffer)
111{
112 if (m_bindings.empty()) {
113 return;
114 }
115
116 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(buffer);
117 if (!vk_buffer) {
119 "GeometryBindingsProcessor requires VKBuffer, got different buffer type");
120 return;
121 }
122
123 for (auto& [name, binding] : m_bindings) {
124 if (!binding.node->needs_gpu_update()) {
126 "Geometry '{}' unchanged, skipping upload", name);
127 continue;
128 }
129
130 auto vertices = binding.node->get_vertex_data();
131
132 if (vertices.empty()) {
133 binding.gpu_vertex_buffer->clear();
134
135 if (binding.node->get_vertex_layout()) {
136 binding.gpu_vertex_buffer->set_vertex_layout(
137 binding.node->get_vertex_layout().value());
138 }
139
141 "Geometry '{}' cleared", name);
142 continue;
143 }
144
145 size_t required_size = vertices.size_bytes();
146 size_t available_size = binding.gpu_vertex_buffer->get_size_bytes();
147
148 if (required_size > available_size) {
149 auto new_size = static_cast<size_t>(required_size * 1.5F);
150
152 "Geometry '{}' growing: resizing GPU buffer from {} → {} bytes",
153 name, available_size, new_size);
154
155 binding.gpu_vertex_buffer->resize(new_size, false);
156 available_size = new_size;
157
158 if (binding.staging_buffer) {
159 binding.staging_buffer->resize(new_size, false);
161 "Resized staging buffer for '{}' to {} bytes", name, new_size);
162 }
163 }
164
165 size_t upload_size = std::min<size_t>(required_size, available_size);
166
168 vertices.data(),
169 upload_size,
170 binding.gpu_vertex_buffer,
171 binding.staging_buffer);
172
173 if (binding.node->get_vertex_layout()) {
174 binding.gpu_vertex_buffer->set_vertex_layout(
175 binding.node->get_vertex_layout().value());
176
178 "Set vertex layout for '{}' ({} vertices, {} attributes)",
179 name,
180 binding.node->get_vertex_count(),
181 binding.node->get_vertex_layout()->attributes.size());
182 } else {
184 "Geometry node '{}' has no vertex layout. "
185 "RenderProcessor may fail without layout info.",
186 name);
187 }
188 binding.node->clear_gpu_update_flag();
189 }
190
191 bool attached_is_target = false;
192 for (const auto& [name, binding] : m_bindings) {
193 if (binding.gpu_vertex_buffer == vk_buffer) {
194 attached_is_target = true;
195 break;
196 }
197 }
198
199 if (!attached_is_target && !m_bindings.empty()) {
200 auto& first_binding = m_bindings.begin()->second;
201 if (first_binding.node->needs_gpu_update()) {
202 auto vertices = first_binding.node->get_vertex_data();
203
204 if (!vertices.empty()) {
205 size_t required_size = vertices.size_bytes();
206 size_t available_size = vk_buffer->get_size_bytes();
207
208 if (required_size > available_size) {
209 auto new_size = static_cast<size_t>(required_size * 1.5F);
210
212 "Fallback geometry growing: resizing GPU buffer from {} → {} bytes",
213 available_size, new_size);
214
215 vk_buffer->resize(new_size, false);
216 available_size = new_size;
217 }
218
219 size_t upload_size = std::min<size_t>(required_size, available_size);
220
221 std::shared_ptr<VKBuffer> staging = vk_buffer->is_host_visible() ? nullptr : first_binding.staging_buffer;
222
224 vertices.data(),
225 upload_size,
226 vk_buffer,
227 staging);
228
229 if (first_binding.node->get_vertex_layout()) {
230 vk_buffer->set_vertex_layout(
231 first_binding.node->get_vertex_layout().value());
232 }
233 }
234 first_binding.node->clear_gpu_update_flag();
235 }
236 }
237}
238
239} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_TRACE(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
std::optional< GeometryBinding > get_binding(const std::string &name) const
Get a specific binding.
std::unordered_map< std::string, GeometryBinding > m_bindings
std::vector< std::string > get_binding_names() const
Get all binding names.
size_t get_binding_count() const
Get number of active bindings.
void bind_geometry_node(const std::string &name, const std::shared_ptr< Nodes::GpuSync::GeometryWriterNode > &node, const std::shared_ptr< VKBuffer > &vertex_buffer)
Bind a geometry node to a GPU vertex buffer.
bool has_binding(const std::string &name) const
Check if a binding exists.
void unbind_geometry_node(const std::string &name)
Remove a geometry binding.
void processing_function(std::shared_ptr< Buffer > buffer) override
BufferProcessor interface - uploads all bound geometries.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
std::shared_ptr< VKBuffer > create_staging_buffer(size_t size)
Create staging buffer for transfers.
void upload_to_gpu(const void *data, size_t size, const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging)
Upload raw data to GPU buffer (auto-detects host-visible vs device-local)
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
std::shared_ptr< Nodes::GpuSync::GeometryWriterNode > node