36 Portal::Graphics::RenderConfig resolve_config(
const Portal::Graphics::RenderConfig& config)
40#ifdef MAYAFLUX_PLATFORM_MACOS
47 if (resolved_config.triangulate) {
48 if (config.vertex_shader.empty())
49 resolved_config.vertex_shader =
"milled_shape.vert.spv";
50 if (config.fragment_shader.empty())
51 resolved_config.fragment_shader =
"milled_shape.frag.spv";
52 resolved_config.geometry_shader.clear();
53 return resolved_config;
56 switch (config.topology) {
58 if (config.vertex_shader.empty())
59 resolved_config.vertex_shader =
"point.vert.spv";
60 if (config.fragment_shader.empty())
61 resolved_config.fragment_shader =
"point.frag.spv";
65 if (config.vertex_shader.empty())
66 resolved_config.vertex_shader =
"line.vert.spv";
68 if (config.fragment_shader.empty())
69 resolved_config.fragment_shader =
"line.frag.spv";
71 if (config.geometry_shader.empty())
72 resolved_config.geometry_shader =
"line.geom.spv";
76 if (config.vertex_shader.empty())
77 resolved_config.vertex_shader =
"triangle.vert.spv";
78 if (config.fragment_shader.empty())
79 resolved_config.fragment_shader =
"triangle.frag.spv";
82 if (config.vertex_shader.empty())
83 resolved_config.vertex_shader =
"point.vert.spv";
84 if (config.fragment_shader.empty())
85 resolved_config.fragment_shader =
"point.frag.spv";
88 return resolved_config;
94 std::shared_ptr<Nodes::Network::NodeNetwork>
network,
95 const std::string& binding_name,
96 float over_allocate_factor)
98 calculate_buffer_size(
network, over_allocate_factor),
100 Kakshya::DataModality::VERTEX_POSITIONS_3D)
102 , m_binding_name(binding_name)
105 error<std::invalid_argument>(
108 std::source_location::current(),
109 "Cannot create NetworkGeometryBuffer with null NodeNetwork");
113 "Created NetworkGeometryBuffer '{}' for {} nodes ({} bytes estimated)",
121 auto self = std::dynamic_pointer_cast<NetworkGeometryBuffer>(shared_from_this());
123 m_processor = std::make_shared<NetworkGeometryProcessor>();
134 chain = std::make_shared<BufferProcessingChain>();
137 chain->set_preferred_token(token);
140 "Setup NetworkGeometryProcessor for '{}' with token {}",
148 auto resolved_config = resolve_config(config);
163 auto* operator_ptr =
m_network->get_operator();
167 return static_cast<uint32_t
>(graphics_op->get_vertex_count());
171 return static_cast<uint32_t
>(
m_network->get_node_count());
175 const std::shared_ptr<Nodes::Network::NodeNetwork>&
network,
176 float over_allocate_factor)
182 size_t node_count =
network->get_node_count();
183 if (node_count == 0) {
185 "NodeNetwork has zero nodes. Buffer will be created with minimum size.");
189 size_t base_size = 0;
191 if (
auto* operator_ptr =
network->get_operator()) {
193 size_t vertex_count = graphics_op->get_vertex_count();
194 auto layout = graphics_op->get_vertex_layout();
196 if (vertex_count > 0 && layout.stride_bytes > 0) {
197 base_size = vertex_count * layout.stride_bytes;
200 "Network geometry buffer sizing: {} vertices × {} bytes = {} bytes (operator: {})",
201 vertex_count, layout.stride_bytes, base_size, operator_ptr->get_type_name());
206 if (base_size == 0) {
208 base_size = node_count * vertex_size;
211 "Network geometry buffer fallback sizing: {} nodes × {} bytes = {} bytes",
212 node_count, vertex_size, base_size);
215 auto allocated_size =
static_cast<size_t>(
216 static_cast<float>(base_size) * over_allocate_factor);
218 if (over_allocate_factor > 1.0F) {
220 "Over-allocated by {}x: {} → {} bytes",
221 over_allocate_factor, base_size, allocated_size);
224 return allocated_size;
229 const auto resolved_config = resolve_config(config);
230 auto self = std::dynamic_pointer_cast<VKBuffer>(shared_from_this());
232 std::shared_ptr<RenderProcessor> render;
237 render->set_vertex_range(0, 0);
242 "Added chain render processor #{} to NetworkGeometryBuffer",
255 uint32_t vertex_offset,
256 uint32_t vertex_count,
257 const std::optional<Kakshya::VertexLayout>& layout,
258 std::vector<Portal::Graphics::DrawRun> runs)
268 const size_t ci =
index - 1;
273 entry.vertex_offset = vertex_offset;
274 entry.vertex_count = vertex_count;
275 entry.render_processor->set_vertex_range(vertex_offset, vertex_count);
276 entry.render_processor->set_runs(std::move(runs));
279 auto self = std::dynamic_pointer_cast<VKBuffer>(shared_from_this());
280 entry.render_processor->set_buffer_vertex_layout(self, *layout);
296 const std::string&
name,
297 size_t element_count,
299 bool double_buffered)
303 "NetworkGeometryBuffer: state field declared with empty name, skipped");
307 if (element_count == 0 || stride_bytes == 0) {
309 "NetworkGeometryBuffer: state field '{}' declares zero element count "
310 "or stride, skipped",
317 "NetworkGeometryBuffer: duplicate state field '{}', later declaration "
326 if (!buffer_service || !buffer_service->allocate_raw_buffer) {
327 error<std::runtime_error>(
330 std::source_location::current(),
331 "NetworkGeometryBuffer requires a valid buffer service");
334 const auto usage_flags =
static_cast<uint32_t
>(
335 static_cast<VkBufferUsageFlags
>(
336 vk::BufferUsageFlagBits::eStorageBuffer
337 | vk::BufferUsageFlagBits::eTransferSrc
338 | vk::BufferUsageFlagBits::eTransferDst));
340 const auto memory_flags =
static_cast<uint32_t
>(
341 static_cast<VkMemoryPropertyFlags
>(vk::MemoryPropertyFlagBits::eDeviceLocal));
344 const size_t field_bytes = element_count * stride_bytes;
345 const uint32_t slot_count = double_buffered ? 2 : 1;
349 .stride_bytes = stride_bytes,
350 .slot_a =
static_cast<uint32_t
>(resources.back_buffers.size()),
355 for (uint32_t i = 0; i < slot_count; ++i) {
356 void* out_buffer =
nullptr;
357 void* out_memory =
nullptr;
358 void* out_mapped =
nullptr;
360 buffer_service->allocate_raw_buffer(
361 field_bytes, usage_flags, memory_flags,
false,
362 out_buffer, out_memory, out_mapped);
365 slot.
buffer =
static_cast<vk::Buffer
>(
static_cast<VkBuffer
>(out_buffer));
366 slot.
memory =
static_cast<vk::DeviceMemory
>(
static_cast<VkDeviceMemory
>(out_memory));
369 resources.back_buffers.push_back(slot);
372 field.slot_b = double_buffered ? field.slot_a + 1 : field.slot_a;
377 "NetworkGeometryBuffer: state field '{}', {} elements, stride {}, {} slot(s), {} bytes",
378 name, element_count, stride_bytes, slot_count, field_bytes * slot_count);
384 const std::string&
name,
const char* context)
const
389 "NetworkGeometryBuffer::{}: no state field named '{}'", context,
name);
406 return it->second.element_count * it->second.stride_bytes;
416 const uint32_t slot = field->read_is_a ? field->slot_a : field->slot_b;
427 const uint32_t slot = field->read_is_a ? field->slot_a : field->slot_b;
438 const uint32_t slot = field->read_is_a ? field->slot_b : field->slot_a;
449 const uint32_t slot = field->read_is_a ? field->slot_b : field->slot_a;
458 "NetworkGeometryBuffer::swap_state: no state field named '{}'",
name);
462 if (it->second.slot_a == it->second.slot_b) {
466 it->second.read_is_a = !it->second.read_is_a;
482 const size_t vertex_count = graphics_op->get_vertex_count();
483 if (vertex_count == 0) {
487 if (!
declare_state(
"hash_cluster_id", vertex_count,
sizeof(uint32_t),
false)) {
491 auto cluster_ids = graphics_op->build_cluster_ids();
492 if (cluster_ids.size() != vertex_count) {
493 cluster_ids.assign(vertex_count, 0U);
496 std::shared_ptr<VKBuffer> staging;
500 cluster_ids.size() *
sizeof(uint32_t),
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
Core::GlobalNetworkConfig network
BufferProcessingChain * chain
std::vector< ChainRenderEntry > m_chain_render_processors
void update_chain_render_range(size_t index, uint32_t vertex_offset, uint32_t vertex_count, const std::optional< Kakshya::VertexLayout > &layout, std::vector< Portal::Graphics::DrawRun > runs={})
Update vertex range for a specific operator chain index.
NetworkGeometryBuffer(std::shared_ptr< Nodes::Network::NodeNetwork > network, const std::string &binding_name="network_geometry", float over_allocate_factor=2.0F)
Create geometry buffer from network.
std::shared_ptr< NetworkGeometryProcessor > m_processor
void add_chain_operator_rendering(const RenderConfig &config)
Add a RenderProcessor for a specific operator chain index.
vk::Buffer write_state_handle(const std::string &name) const
Handle a stage should write the named state field to.
size_t get_state_bytes(const std::string &name) const
Byte size of one slot of the named state field, or 0 if undeclared.
uint32_t get_vertex_count() const
Get current vertex count (aggregated from all network nodes)
bool declare_state(const std::string &name, size_t element_count, size_t stride_bytes, bool double_buffered=true)
Declare a named auxiliary state field alongside the vertex data.
std::shared_ptr< Nodes::Network::NodeNetwork > m_network
VKBufferResources::GenerationSlot read_state_slot(const std::string &name) const
Full back_buffers slot a stage should read the named state field from.
const StateField * find_state_field(const std::string &name, const char *context) const
Resolve a declared state field by name.
bool has_state(const std::string &name) const
Whether a state field of this name was declared.
vk::Buffer read_state_handle(const std::string &name) const
Handle a stage should read the named state field from.
void setup_rendering(const RenderConfig &config)
Setup rendering with RenderProcessor.
VKBufferResources::GenerationSlot write_state_slot(const std::string &name) const
Full back_buffers slot a stage should write the named state field to.
std::string m_binding_name
void swap_state(const std::string &name)
Exchange read and write slots for the named state field.
std::unordered_map< std::string, StateField > m_state_fields
void wire_field_operators()
Find the first GpuFieldOperator in the network's operator chain and wire its compute stages: a Vertex...
void update_render_runs(std::vector< Portal::Graphics::DrawRun > runs)
Hand the primary processor its spans, without touching its range.
std::shared_ptr< RenderProcessor > get_chain_render_processor(size_t index) const
Get RenderProcessor for a specific operator chain index.
static size_t calculate_buffer_size(const std::shared_ptr< Nodes::Network::NodeNetwork > &network, float over_allocate_factor)
Calculate initial buffer size based on network node count.
void setup_processors(ProcessingToken token) override
Initialize the buffer and its processors.
bool ensure_cluster_ids()
Ensure the hash_cluster_id state field exists, declaring and populating it from the network's own pri...
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
void set_default_processor(const std::shared_ptr< BufferProcessor > &processor) override
Set the buffer's default processor.
Portal::Graphics::RenderConfig RenderConfig
vk::DeviceSize get_size_bytes() const
void set_processing_chain(const std::shared_ptr< BufferProcessingChain > &chain, bool force=false) override
Replace the buffer's processing chain.
void apply_render_config(const RenderConfig &config, const ShaderConfig &shader_config)
Configure the internal m_render_processor from a RenderConfig.
std::shared_ptr< RenderProcessor > m_render_processor
void set_default_render_config(const RenderConfig &config)
Called by derived classes to set their context-specific defaults.
const VKBufferResources & get_buffer_resources() const
Get all buffer resources at once (read-only)
Vulkan-backed buffer wrapper used in processing chains.
Operator that produces GPU-renderable geometry.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
void upload_back_buffer(const VKBufferResources::GenerationSlot &slot, const void *data, size_t size, std::shared_ptr< VKBuffer > &staging)
Upload host memory into a raw back_buffers slot.
@ BufferManagement
Buffer Management (Buffers::BufferManager, creating buffers)
@ Init
Engine/subsystem initialization.
@ Buffers
Buffers, Managers, processors and processing chains.
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
std::vector< GenerationSlot > back_buffers
Vertex type for point primitives (POINT_LIST topology)
static VertexLayout for_lines(uint32_t stride=60)
Factory: layout for LineVertex (position, color, thickness, uv, normal, tangent)
bool triangulate
Reduce supplied spans to triangles before drawing them.
Unified rendering configuration for graphics buffers.
Backend buffer management service interface.