MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FormaBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Core {
7class Window;
8}
9
10namespace MayaFlux::Buffers {
11class FormaProcessor;
12class RenderProcessor;
13
14/**
15 * @class FormaBuffer
16 * @brief VKBuffer for 2D screen-space Forma geometry.
17 *
18 * Encodes the invariants that hold for all Forma geometry:
19 * - No depth test, no depth write, no view transform.
20 * - Alpha blending enabled on the RenderProcessor.
21 * - Topology fixed at construction (determines default shaders).
22 *
23 * Provides write_bytes() as the clean write interface for Mapped::sync(),
24 * replacing the raw set_data path on plain VKBuffer.
25 *
26 * Usage:
27 * @code
28 * auto buf = std::make_shared<FormaBuffer>(
29 * initial_capacity_bytes,
30 * Portal::Graphics::PrimitiveTopology::TRIANGLE_STRIP);
31 * buf->setup_processors(ProcessingToken::GRAPHICS_BACKEND);
32 * buf->setup_rendering({ .target_window = window });
33 * @endcode
34 */
35class MAYAFLUX_API FormaBuffer : public Buffers::VKBuffer {
36public:
37 /**
38 * @brief Construct a FormaBuffer.
39 * @param capacity_bytes Initial buffer capacity. Size the buffer for the
40 * maximum expected vertex count from the geometry
41 * function. write_bytes() will warn if exceeded.
42 * @param topology Primitive topology. Determines default shaders
43 * selected in setup_rendering().
44 */
46 size_t capacity_bytes,
48
49 /**
50 * @brief Construct a FormaBuffer.
51 * @param topology Primitive topology. Determines default shaders
52 * selected in setup_rendering().
53 */
56
57 ~FormaBuffer() override = default;
58
59 FormaBuffer(const FormaBuffer&) = delete;
63
64 /**
65 * @brief Register with the graphics subsystem.
66 * Creates a BufferUploadProcessor as default processor.
67 */
68 void setup_processors(ProcessingToken token) override;
69
70 /**
71 * @brief Attach a RenderProcessor targeting the given window.
72 *
73 * Selects default shaders from topology set at construction. Always
74 * enables alpha blending, disables depth testing. Caller may override
75 * shaders via config fields.
76 *
77 * TRIANGLE_LIST/TRIANGLE_STRIP picks its fragment shader from texture
78 * state (forma_multi/forma_textured/triangle.frag) regardless of
79 * @c triangulate -- PrimitiveMill's triangle pass copies UV unchanged,
80 * so texturing stays correct either way; it never falls back to
81 * milled_shape.frag, which would blank every textured scene.
82 *
83 * POINT_LIST does switch under triangulate, to milled_shape.vert plus
84 * milled_shape.frag/_textured/_multi depending on texture state
85 * (point.frag's gl_PointCoord is meaningless once forced TRIANGLE_LIST).
86 * The multi variant's array index shares the scalar slot PrimitiveMill
87 * reads as point size -- set_mill_spec(use_vertex_extent = false)
88 * decouples them; left default, size and index are the same number.
89 */
90 void setup_rendering(const RenderConfig& config);
91
92 /**
93 * @brief Write vertex bytes into the buffer.
94 *
95 * Called by Mapped::sync() each time the geometry function produces
96 * new vertex data. Copies bytes into the mapped host-visible region
97 * and marks the dirty range for flush on the next graphics tick.
98 *
99 * @param bytes Raw interleaved vertex bytes. Must not exceed the
100 * capacity set at construction.
101 */
102 void submit(const std::vector<uint8_t>& bytes);
103
105
106 /**
107 * @brief Add a block of vertices that shares this buffer with the others.
108 *
109 * submit() writes a default block of its own, so a buffer used only
110 * through submit() holds one. Blocks share the buffer's topology and are
111 * uploaded together; each can be updated, hidden or reordered without
112 * touching the rest. Several blocks cost one draw when they are adjacent,
113 * visible and in order.
114 *
115 * Valid once setup_processors() has run.
116 *
117 * @param bytes Whole interleaved vertices matching the topology; a trailing
118 * partial vertex is dropped.
119 * @param topology Topology of this block; the buffer's when omitted. A
120 * different topology needs setup_rendering with triangulate,
121 * which draws mixed blocks as one batch.
122 * @return Id of the block, or 0 when the buffer has no processor yet.
123 */
124 SliceId add_slice(const std::vector<uint8_t>& bytes,
125 std::optional<Portal::Graphics::PrimitiveTopology> topology = std::nullopt);
126
127 /** @brief Replace a block's vertices; later blocks shift if the size changes. */
128 void update_slice(SliceId id, const std::vector<uint8_t>& bytes);
129
130 /** @brief Number of blocks, 0 before setup_processors(). */
131 [[nodiscard]] size_t slice_count() const noexcept;
132
133 /** @brief True when @p id names a live block. */
134 [[nodiscard]] bool has_slice(SliceId id) const noexcept;
135
136 /** @brief Remove a block; later blocks shift down. */
137 void remove_slice(SliceId id);
138
139 /** @brief Hide or show a block without moving its data. */
140 void set_slice_visible(SliceId id, bool visible);
141
142 /** @brief Draw a block after every other. */
143 void bring_slice_to_front(SliceId id);
144
145 /** @brief Draw a block before every other. */
146 void send_slice_to_back(SliceId id);
147
148 /**
149 * @brief Supply a texture to be bound on the next graphics tick.
150 *
151 * The image is owned externally — a TextBuffer's VKImage from
152 * InkPress, a loaded asset, a render target, anything. FormaProcessor
153 * forwards it to the RenderProcessor on the next processing_function
154 * call. Calling again replaces the previous binding.
155 *
156 * @param image GPU image to bind. nullptr clears the binding.
157 * @param binding Descriptor name in the shader (e.g. "texSampler").
158 */
159 void set_texture(std::shared_ptr<Core::VKImage> image, std::string binding);
160
161 /**
162 * @brief Bind a texture to a slot in the multi-texture array at runtime.
163 *
164 * Valid only when setup_rendering was called with additional_textures.
165 * @p array_index is 0-based into the array declared at setup time:
166 * index 0 = weight 1, index 1 = weight 2, etc.
167 *
168 * @param array_index Zero-based index into the textures[] array.
169 * @param image GPU image. Must be GPU-resident.
170 */
171 void bind_texture(uint32_t array_index, const std::shared_ptr<Core::VKImage>& image);
172
173 [[nodiscard]] Portal::Graphics::PrimitiveTopology topology() const { return m_topology; }
174
175 /**
176 * @brief Submit a contiguous sequence of vertices.
177 *
178 * Accepts any contiguous range of trivially-copyable vertex structs:
179 * std::array, std::vector, std::span, or a raw pointer + count pair.
180 * Reinterprets the data as bytes and forwards to the primary submit().
181 *
182 * @tparam V Vertex type. Must be trivially copyable.
183 * @param vertices Contiguous range of V.
184 */
185 template <typename V>
186 requires std::ranges::contiguous_range<V>
187 && std::is_trivially_copyable_v<std::ranges::range_value_t<V>>
188 void submit(const V& vertices)
189 {
190 const auto* src = reinterpret_cast<const uint8_t*>(std::ranges::data(vertices));
191 const size_t n = std::ranges::size(vertices) * sizeof(std::ranges::range_value_t<V>);
192 submit(std::vector<uint8_t>(src, src + n));
193 }
194
195 /**
196 * @brief Submit a single vertex struct.
197 *
198 * Convenience for point-list buffers and single-primitive cases where
199 * constructing a container for one vertex is unnecessary.
200 *
201 * @tparam V Vertex type. Must be trivially copyable.
202 * @param vertex The vertex to write.
203 */
204 template <typename V>
205 requires std::is_trivially_copyable_v<V>
206 && (!std::ranges::range<V>)
207 void submit(const V& vertex)
208 {
209 const auto* src = reinterpret_cast<const uint8_t*>(&vertex);
210 submit(std::vector<uint8_t>(src, src + sizeof(V)));
211 }
212
213private:
215 std::shared_ptr<Buffers::FormaProcessor> m_processor;
216
217 /// @brief Geometry bytes from submit() before setup_processors(). Drained in setup_processors().
218 std::vector<uint8_t> m_pending_geometry;
219
220 /// @brief Textures from set_texture() before setup_processors(). Drained in setup_processors().
221 std::vector<std::pair<std::shared_ptr<Core::VKImage>, std::string>> m_pending_textures;
222};
223
224} // namespace MayaFlux::Buffers
IO::ImageData image
Definition Decoder.cpp:47
const uint32_t * src
PrimitiveTopology topology
std::vector< uint8_t > m_pending_geometry
Geometry bytes from submit() before setup_processors(). Drained in setup_processors().
FormaBuffer & operator=(FormaBuffer &&)=delete
std::shared_ptr< Buffers::FormaProcessor > m_processor
FormaBuffer(FormaBuffer &&)=delete
FormaBuffer & operator=(const FormaBuffer &)=delete
~FormaBuffer() override=default
Portal::Graphics::PrimitiveTopology m_topology
void submit(const V &vertices)
Submit a contiguous sequence of vertices.
FormaBuffer(const FormaBuffer &)=delete
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().
void submit(const V &vertex)
Submit a single vertex struct.
VKBuffer for 2D screen-space Forma geometry.
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:76
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
PrimitiveTopology
Vertex assembly primitive topology.
Unified rendering configuration for graphics buffers.