MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RelaxationStepProcessor.hpp
Go to the documentation of this file.
1#pragma once
2
4
5namespace MayaFlux::Buffers {
6
7class RelaxationGridBuffer;
8
9/**
10 * @class RelaxationStepProcessor
11 * @brief ComputeProcessor specialization driving one generation step of a
12 * RelaxationGridBuffer per dispatch.
13 *
14 * Pipeline and descriptor set layout creation follow the normal
15 * ShaderProcessor path via m_config.bindings ("state_in" at binding 0,
16 * "state_out" at binding 1), identical to how SDFFieldProcessor declares
17 * its "sdf_grid" binding. Because the two state buffers are raw handle
18 * pairs with no VKBuffer wrapper, the per-generation WRITE of those two
19 * descriptor bindings is issued directly via
20 * ShaderFoundry::update_descriptor_buffer in on_before_execute, bypassing
21 * ShaderProcessor::bind_buffer / m_bound_buffers entirely for these two
22 * names.
23 *
24 * After dispatch, on_after_execute swaps which back_buffers index is
25 * considered front and, if requested via
26 * RelaxationGridBuffer::request_snapshot(), stages a device-to-host
27 * download of the newly-front state buffer using a lazily-created,
28 * processor-owned staging VKBuffer, reused across requests.
29 *
30 * Runs on the normal buffer processing cycle. Whether a generation
31 * actually advances this cycle is decided by an optional step predicate,
32 * checked in on_before_execute after the descriptor write. Returning
33 * false there skips execute_shader entirely for that cycle: no dispatch,
34 * no swap, no snapshot check.
35 */
36class MAYAFLUX_API RelaxationStepProcessor : public ComputeProcessor {
37public:
38 /** @brief Callable deciding whether the current cycle advances a generation. */
39 using StepPredicate = std::function<bool()>;
40
41 /**
42 * @struct GridExtent
43 * @brief Leading push constant fields every relaxation rule shader
44 * receives: grid width then height, at offset 0.
45 *
46 * Matches the convention AsmGenerator::emit_stencil_body reads for
47 * generated Stencil kernels, and which hand-written rule shaders are
48 * expected to declare as their first two push constant fields. Rule
49 * specific parameters follow at offset 8.
50 */
51 struct GridExtent {
52 uint32_t width;
53 uint32_t height;
54 };
55
56 /**
57 * @brief Construct a step processor for the given rule shader file.
58 * @param shader_path Path to the compute shader implementing the rule.
59 * @param workgroup_x Local workgroup size along X, forwarded to ComputeProcessor.
60 */
61 explicit RelaxationStepProcessor(const std::string& shader_path, uint32_t workgroup_x = 16);
62
63 /**
64 * @brief Construct a step processor from a generated ShaderSpec.
65 * @param spec ShaderSpec implementing the rule, produced by a factory
66 * such as a Stencil-based generated rule (e.g. Jacobi diffusion)
67 * or by ShaderSpec::Assemble with MF_KERNEL for branchy rules.
68 *
69 * Forwards to ComputeProcessor(spec) directly; workgroup sizing comes
70 * from spec.workgroup_size rather than a separate parameter.
71 */
73
74 /**
75 * @brief Set the predicate deciding whether this cycle advances a
76 * generation.
77 * @param predicate Callable returning true to step, false to skip.
78 * Pass nullptr to always step (default).
79 *
80 * Checked once per on_before_execute, after the state descriptor
81 * bindings have already been written for the current front/back
82 * assignment. Returning false skips execute_shader for that cycle
83 * without side effects beyond the descriptor write already performed.
84 */
85 void set_step_predicate(StepPredicate predicate) { m_step_predicate = std::move(predicate); }
86
87protected:
88 /**
89 * @brief Write the state_in / state_out descriptor bindings for the
90 * current front/back assignment, then evaluate the step
91 * predicate.
92 * @param cmd_id Command buffer this cycle's dispatch will be recorded into.
93 * @param buffer The attached RelaxationGridBuffer, received as VKBuffer.
94 * @return True if execute_shader should proceed this cycle.
95 */
96 bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr<VKBuffer>& buffer) override;
97
98 /**
99 * @brief Swap front/back generation index and, if requested, stage a
100 * snapshot download of the buffer just written.
101 * @param cmd_id Command buffer the completed dispatch was recorded into.
102 * @param buffer The attached RelaxationGridBuffer, received as VKBuffer.
103 */
104 void on_after_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr<VKBuffer>& buffer) override;
105
106 /**
107 * @brief Write the state_in / state_out descriptor bindings for the
108 * current front/back assignment.
109 *
110 * Called once after the descriptor set is created, and again after
111 * any reallocation of the attached RelaxationGridBuffer's back_buffers.
112 */
113 void on_descriptors_created() override;
114
115 /**
116 * @brief When attached to a RelaxationGridBuffer, sets up the dispatch
117 * configuration to cover the entire grid with a single workgroup
118 * dimension along Y and Z, and a workgroup size along X that is
119 * either the default 16 or the value supplied at construction.
120 * @param buffer The attached buffer, expected to be a RelaxationGridBuffer.
121 */
122 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
123
124 /**
125 * @brief Write the state descriptors for the current front/back
126 * assignment, then run the normal shader processing path.
127 *
128 * The descriptor write must precede execute_shader's
129 * vkCmdBindDescriptorSets. Writing from on_before_execute updates a set
130 * already bound into the open command buffer, which the driver has
131 * consumed by then, freezing the bindings at whatever
132 * on_descriptors_created wrote.
133 */
134 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
135
136private:
137 /**
138 * @brief Issue direct ShaderFoundry descriptor writes for state_in and
139 * state_out against the grid's current front/back raw buffers.
140 * @param grid The RelaxationGridBuffer whose state buffers are being bound.
141 */
142 void write_state_descriptors(const std::shared_ptr<RelaxationGridBuffer>& grid);
143
144 /**
145 * @brief Size the push constant block to at least GridExtent and write
146 * the attached grid's dimensions into its leading 8 bytes.
147 *
148 * Called from on_attach, the first point at which grid dimensions are
149 * known. A ShaderSpec-constructed processor already carries
150 * spec.push_constant_bytes in m_config; that size is preserved and only
151 * the leading extent fields are written, leaving trailing rule
152 * parameters available to set_push_constant_data_raw at any offset
153 * past sizeof(GridExtent).
154 */
155 void write_grid_extent_constants();
156
157 /**
158 * @brief Lazily-created, reused host-visible staging buffer for
159 * snapshot downloads. Sized to RelaxationGridBuffer::get_state_bytes()
160 * on first use.
161 */
162 std::shared_ptr<VKBuffer> m_snapshot_staging;
163
164 StepPredicate m_step_predicate; ///< Optional gate deciding whether a given cycle advances a generation
165 std::shared_ptr<RelaxationGridBuffer> m_grid; ///< The attached RelaxationGridBuffer, cached for descriptor writes and snapshot staging.
166};
167
168} // namespace MayaFlux::Buffers
Specialized ShaderProcessor for Compute Pipelines.
std::function< bool()> StepPredicate
Callable deciding whether the current cycle advances a generation.
StepPredicate m_step_predicate
Optional gate deciding whether a given cycle advances a generation.
std::shared_ptr< RelaxationGridBuffer > m_grid
The attached RelaxationGridBuffer, cached for descriptor writes and snapshot staging.
void set_step_predicate(StepPredicate predicate)
Set the predicate deciding whether this cycle advances a generation.
std::shared_ptr< VKBuffer > m_snapshot_staging
Lazily-created, reused host-visible staging buffer for snapshot downloads.
ComputeProcessor specialization driving one generation step of a RelaxationGridBuffer per dispatch.
Leading push constant fields every relaxation rule shader receives: grid width then height,...
Complete declarative description of a generated compute shader.