MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FormaBuffer.cpp
Go to the documentation of this file.
1#include "FormaBuffer.hpp"
2
7
9
11
12namespace MayaFlux::Buffers {
13
14namespace {
15 constexpr size_t k_capacity_bytes = 4 * 1024 * 1024; // 4 MiB default capacity, can be overridden by constructor
16}
17
19 size_t capacity_bytes,
21 : VKBuffer(capacity_bytes, Buffers::VKBuffer::Usage::VERTEX,
22 Kakshya::DataModality::VERTEX_POSITIONS_3D)
23 , m_topology(topology)
24{
25}
26
32
34{
35 auto proc = std::make_shared<Buffers::FormaProcessor>(m_topology);
37 m_processor = proc;
38
40 if (!chain) {
41 chain = std::make_shared<Buffers::BufferProcessingChain>();
43 }
44 chain->set_preferred_token(token);
45
46 if (!m_pending_geometry.empty()) {
48 m_pending_geometry.clear();
49 }
50
51 for (auto& [img, binding] : m_pending_textures)
52 m_processor->set_texture(std::move(img), std::move(binding));
53
54 m_pending_textures.clear();
55}
56
58{
59 RenderConfig resolved = config;
60 resolved.topology = m_topology;
61
62 const bool single_tex = !config.default_texture_binding.empty();
63 const auto multi_count = static_cast<uint32_t>(config.additional_textures.size());
64 const bool multi_tex = multi_count > 0;
65
66 switch (resolved.topology) {
68 if (resolved.triangulate) {
69 if (resolved.vertex_shader.empty())
70 resolved.vertex_shader = "milled_shape.vert.spv";
71 if (resolved.fragment_shader.empty()) {
72 if (multi_tex) {
73 resolved.fragment_shader = "milled_shape_multi.frag.spv";
74 } else if (single_tex) {
75 resolved.fragment_shader = "milled_shape_textured.frag.spv";
76 } else {
77 resolved.fragment_shader = "milled_shape.frag.spv";
78 }
79 }
80 } else {
81 if (resolved.vertex_shader.empty())
82 resolved.vertex_shader = "point.vert.spv";
83 if (resolved.fragment_shader.empty())
84 resolved.fragment_shader = "point.frag.spv";
85 }
86 break;
87
90 if (resolved.vertex_shader.empty())
91 resolved.vertex_shader = "line.vert.spv";
92 if (resolved.fragment_shader.empty())
93 resolved.fragment_shader = "line.frag.spv";
94#ifdef MAYAFLUX_PLATFORM_MACOS
95 resolved.triangulate = true;
96#endif
97
98 if (resolved.triangulate) {
99 resolved.geometry_shader.clear();
100 } else if (resolved.geometry_shader.empty()) {
101 resolved.geometry_shader = "line.geom.spv";
102 }
103
104 break;
105
108 if (resolved.vertex_shader.empty())
109 resolved.vertex_shader = multi_tex ? "triangle_multi.vert.spv" : "triangle.vert.spv";
110 if (resolved.fragment_shader.empty()) {
111 if (multi_tex) {
112 resolved.fragment_shader = "forma_multi.frag.spv";
113 } else if (single_tex) {
114 resolved.fragment_shader = "forma_textured.frag.spv";
115 } else {
116 resolved.fragment_shader = "triangle.frag.spv";
117 }
118 }
119 break;
120
121 default:
122 if (resolved.vertex_shader.empty())
123 resolved.vertex_shader = "point.vert.spv";
124 if (resolved.fragment_shader.empty())
125 resolved.fragment_shader = "point.frag.spv";
126 break;
127 }
128
129 ShaderConfig sc { resolved.vertex_shader };
130 if (multi_tex) {
131 const uint32_t total = single_tex ? 1 + multi_count : multi_count;
132 sc.bindings["textures"] = ShaderBinding(
133 0, 1, vk::DescriptorType::eCombinedImageSampler, total);
134 } else if (single_tex) {
135 sc.bindings[config.default_texture_binding] = ShaderBinding(
136 0, 1, vk::DescriptorType::eCombinedImageSampler);
137 }
138
139 apply_render_config(resolved, sc);
140 m_render_processor->enable_alpha_blending();
141
142 if (multi_tex) {
143 uint32_t slot = 1;
144 if (single_tex && !config.default_texture_binding.empty()) {
145 auto it = std::ranges::find_if(config.additional_textures,
146 [&](const auto& p) { return p.first == config.default_texture_binding; });
147 if (it != config.additional_textures.end()) {
148 m_render_processor->bind_texture(slot, it->second);
149 ++slot;
150 }
151 }
152 for (const auto& [name, img] : config.additional_textures) {
153 if (single_tex && name == config.default_texture_binding)
154 continue;
155
156 if (img)
157 m_render_processor->bind_texture(slot, img);
158
159 ++slot;
160 }
161 }
162
163 get_processing_chain()->add_final_processor(m_render_processor, shared_from_this());
165}
166
167void FormaBuffer::submit(const std::vector<uint8_t>& bytes)
168{
169 if (!m_processor) {
170 m_pending_geometry = bytes;
172 "FormaBuffer::submit called before setup_processors, storing {} bytes for later submission", bytes.size());
173 return;
174 }
175 m_processor->set_bytes(bytes);
176}
177
179 const std::vector<uint8_t>& bytes,
180 std::optional<Portal::Graphics::PrimitiveTopology> topology)
181{
182 if (!m_processor) {
184 "FormaBuffer::add_slice called before setup_processors");
185 return 0;
186 }
187 return m_processor->add_slice(bytes, topology);
188}
189
190void FormaBuffer::update_slice(SliceId id, const std::vector<uint8_t>& bytes)
191{
192 if (m_processor)
193 m_processor->update_slice(id, bytes);
194}
195
196size_t FormaBuffer::slice_count() const noexcept
197{
198 return m_processor ? m_processor->slice_count() : 0;
199}
200
201bool FormaBuffer::has_slice(SliceId id) const noexcept
202{
203 return m_processor && m_processor->has_slice(id);
204}
205
207{
208 if (m_processor)
209 m_processor->remove_slice(id);
210}
211
213{
214 if (m_processor)
215 m_processor->set_slice_visible(id, visible);
216}
217
219{
220 if (m_processor)
221 m_processor->bring_slice_to_front(id);
222}
223
225{
226 if (m_processor)
227 m_processor->send_slice_to_back(id);
228}
229
230void FormaBuffer::set_texture(std::shared_ptr<Core::VKImage> image, std::string binding)
231{
232 if (!m_processor) {
233 m_pending_textures.emplace_back(std::move(image), std::move(binding));
235 "FormaBuffer::set_texture called before setup_processors, storing texture for later submission");
236 return;
237 }
238 m_processor->set_texture(std::move(image), std::move(binding));
239}
240
241void FormaBuffer::bind_texture(uint32_t array_index, const std::shared_ptr<Core::VKImage>& image)
242{
244 m_render_processor->bind_texture(1 + array_index, image);
245}
246
247} // namespace MayaFlux::Buffers
#define MF_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
IO::ImageData image
Definition Decoder.cpp:47
BufferProcessingChain * chain
uint32_t total
PrimitiveTopology topology
std::string name
Definition VKDevice.cpp:123
void set_slice_visible(SliceId id, bool visible)
Hide or show a block without moving its data.
bool has_slice(SliceId id) const noexcept
True when id names a live block.
void submit(const std::vector< uint8_t > &bytes)
Write vertex bytes into the buffer.
void update_slice(SliceId id, const std::vector< uint8_t > &bytes)
Replace a block's vertices; later blocks shift if the size changes.
std::vector< uint8_t > m_pending_geometry
Geometry bytes from submit() before setup_processors(). Drained in setup_processors().
std::shared_ptr< Buffers::FormaProcessor > m_processor
void setup_rendering(const RenderConfig &config)
Attach a RenderProcessor targeting the given window.
void bind_texture(uint32_t array_index, const std::shared_ptr< Core::VKImage > &image)
Bind a texture to a slot in the multi-texture array at runtime.
Portal::Graphics::PrimitiveTopology topology() const
void set_texture(std::shared_ptr< Core::VKImage > image, std::string binding)
Supply a texture to be bound on the next graphics tick.
SliceId add_slice(const std::vector< uint8_t > &bytes, std::optional< Portal::Graphics::PrimitiveTopology > topology=std::nullopt)
Add a block of vertices that shares this buffer with the others.
void bring_slice_to_front(SliceId id)
Draw a block after every other.
void setup_processors(ProcessingToken token) override
Register with the graphics subsystem.
Portal::Graphics::PrimitiveTopology m_topology
FormaBuffer(size_t capacity_bytes, Portal::Graphics::PrimitiveTopology topology)
Construct a FormaBuffer.
void remove_slice(SliceId id)
Remove a block; later blocks shift down.
size_t slice_count() const noexcept
Number of blocks, 0 before setup_processors().
void send_slice_to_back(SliceId id)
Draw a block before every other.
std::vector< std::pair< std::shared_ptr< Core::VKImage >, std::string > > m_pending_textures
Textures from set_texture() before setup_processors(). Drained in setup_processors().
VKBuffer for 2D screen-space Forma geometry.
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
Definition VKBuffer.cpp:271
void set_default_processor(const std::shared_ptr< BufferProcessor > &processor) override
Set the buffer's default processor.
Definition VKBuffer.cpp:255
void set_processing_chain(const std::shared_ptr< BufferProcessingChain > &chain, bool force=false) override
Replace the buffer's processing chain.
Definition VKBuffer.cpp:276
void apply_render_config(const RenderConfig &config, const ShaderConfig &shader_config)
Configure the internal m_render_processor from a RenderConfig.
Definition VKBuffer.cpp:344
std::shared_ptr< RenderProcessor > m_render_processor
Definition VKBuffer.hpp:654
void set_default_render_config(const RenderConfig &config)
Called by derived classes to set their context-specific defaults.
Definition VKBuffer.hpp:631
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:76
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
constexpr size_t k_capacity_bytes
Definition Atelier.hpp:37
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
PrimitiveTopology
Vertex assembly primitive topology.
Describes how a VKBuffer binds to a shader descriptor.
std::vector< std::pair< std::string, std::shared_ptr< Core::VKImage > > > additional_textures
bool triangulate
Reduce supplied spans to triangles before drawing them.
Unified rendering configuration for graphics buffers.