76 ks.
raw = std::string(stringified);
79 const auto bracket = stringified.find(
'[');
80 const auto paren_open = stringified.find(
'(', bracket);
81 if (paren_open == std::string_view::npos)
84 std::size_t depth = 1;
85 std::size_t paren_close = paren_open + 1;
86 while (paren_close < stringified.size() && depth > 0) {
87 if (stringified[paren_close] ==
'(') {
89 }
else if (stringified[paren_close] ==
')') {
96 const auto params_text = stringified.substr(paren_open + 1, paren_close - paren_open - 1);
99 auto extract_name = [](std::string_view param) -> std::string {
101 auto end = param.find_last_not_of(
" \t\n\r");
102 if (end == std::string_view::npos)
104 param = param.substr(0, end + 1);
106 auto sep = param.find_last_of(
" *\t");
107 if (sep == std::string_view::npos)
108 return std::string(param);
109 return std::string(param.substr(sep + 1));
112 std::size_t start = 0;
113 while (start < params_text.size()) {
115 int angle = 0, paren = 0;
116 std::size_t pos = start;
117 while (pos < params_text.size()) {
118 char c = params_text[pos];
121 }
else if (c ==
'>') {
123 }
else if (c ==
'(') {
125 }
else if (c ==
')') {
127 }
else if (c ==
',' && angle == 0 && paren == 0) {
132 auto name = extract_name(params_text.substr(start, pos - start));
135 start = (pos < params_text.size()) ? pos + 1 : pos;
139 const auto brace_open = stringified.find(
'{', paren_close);
140 if (brace_open == std::string_view::npos)
144 std::size_t brace_close = brace_open + 1;
145 while (brace_close < stringified.size() && depth > 0) {
146 if (stringified[brace_close] ==
'{') {
148 }
else if (stringified[brace_close] ==
'}') {
155 ks.
body = std::string(stringified.substr(brace_open + 1, brace_close - brace_open - 1));
385 .name = std::move(name),
386 .direction = direction,
388 .modality = modality,
401 .name = std::move(name),
418 .name = std::move(name),
419 .direction = direction,
432 m_pc_fields.push_back({ .name = std::move(name), .format = format });
462 uint32_t pc_bytes = 0;
472 .push_constant_bytes = pc_bytes,
503#define MF_KERNEL(lambda) \
504 MayaFlux::Portal::Graphics::KernelSource::parse(#lambda)
Assemble & op(KernelOp o)
Set the named operation the emitter will lower to SPIR-V.
Assemble & start_set(uint32_t s)
std::vector< BindingSlot > m_bindings
ShaderSpec build()
Finalise and return the ShaderSpec.
Assemble & pc(std::string name, Kakshya::GpuDataFormat format)
Declare a push constant field with explicit format.
Assemble & ssbo(std::string name, BindingDirection direction, Kakshya::GpuDataFormat format, Kakshya::DataModality modality=Kakshya::DataModality::SCALAR_F32)
Declare an SSBO binding.
Assemble & kernel(KernelSource ks)
Supply a user kernel via MF_KERNEL.
Assemble & pc(std::string name)
Declare a float push constant field.
std::vector< PushConstantField > m_pc_fields
Assemble & workgroup(uint32_t x, uint32_t y=1, uint32_t z=1)
Override workgroup size.
std::array< uint32_t, 3 > m_workgroup
Assemble & tmpl(KernelTemplate t)
Set the kernel template.
Assemble & texture(std::string name)
Declare a sampled image binding (sampler2D).
std::optional< KernelSource > m_kernel
Assemble & storage_image(std::string name, BindingDirection direction=BindingDirection::Output)
Declare a storage image binding (image2D).
Assemble & start_binding(uint32_t n)
Fluent assembler producing a ShaderSpec.
size_t gpu_data_format_bytes(GpuDataFormat fmt) noexcept
Byte size of one element of a GpuDataFormat.
DataModality
Data modality types for cross-modal analysis.
@ SCALAR_F32
Single-channel float data.
@ TEXTURE_2D
2D texture data
@ IMAGE_2D
2D image (grayscale or single channel)
GpuDataFormat
GPU data formats with explicit precision levels.
KernelTemplate
Structural shape of the generated compute kernel.
@ Scan
Inclusive prefix scan over one InOut SSBO, double-buffered Hillis-Steele in shared memory.
@ Convolve2D
2D separable or non-separable convolution; kernel weights in SSBO, radius in PC
@ Reduction
f(x[0..n]) -> scalar; shared-memory tree reduction
@ Elementwise
f(x[i]) -> y[i]; one thread per element
@ Stencil
f(x[i-k..i+k]) -> y[i]; neighbourhood reads, radius in PC
@ GeometryEmit
Writes into vertex SSBO with atomic counter.
@ BitonicSort
Bitonic sort network; one thread per element.
BindingDirection
Data flow direction for a shader binding slot.
KernelOp
Named operation the SPIR-V emitter knows how to lower to opcodes.
@ CompareGE
out[ch] = pixel[ch] >= pc[0] ? 1.0 : 0.0
@ ChannelDot
out = dot(pixel.rgba, pc[0..3]) broadcast to all channels
@ ScanSum
Inclusive prefix sum: shared[i] = sum(x[0..i])
@ IndexScale
out[i] = float(i) * a[i].
@ CompareGEPreserve
out[ch] = pixel[ch] >= pc[0] ? pc[1] : pixel[ch]
@ MaxIndex
Reduction variant: finds max value AND its index.
@ ChannelReplicate
out = pixel[pc_channel_index].xxxx (single channel to all)
Kakshya::DataModality modality
Kakshya::GpuDataFormat format
BindingDirection direction
Declaration of one SSBO or image binding in a generated shader.
static KernelSource parse(std::string_view stringified)
Parse parameter names and body from a stringified lambda.
std::vector< std::string > param_names
Parsed representation of a user-supplied kernel lambda.
Kakshya::GpuDataFormat format
One field in the generated push constant block.
uint32_t push_constant_bytes
std::vector< PushConstantField > pc_fields
std::vector< BindingSlot > bindings
std::array< uint32_t, 3 > workgroup_size
std::optional< KernelSource > kernel
When set, KernelOp is ignored.
Complete declarative description of a generated compute shader.