Examples
Learn from a complete pipeline
Each example builds a host application with embedded native GLSL shaders. Its default execution path uses the CPU. Select a supported headless GPU profile to run the same pipeline on a GPU. Start with the buffer pipeline, then choose an operation close to your application.
# Build the examples and their embedded shaders in Release mode.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
# Compile the configured applications and CPU adapters.
cmake --build build -j
# Run three linked stages on the CPU.
./build/example_pipeline
# Run the same application and shaders on an ES 3.1 GPU.
./build/example_pipeline --gpu es31
Supported profile arguments are es31, es32, gl43, gl45 and gl46. The driver supplies the requested GPU context. CPU examples use host resources. Each excerpt links to complete numbered source files.
Connect the complete pipeline. Keep each kernel alive while a stage refers to it. Read completed resources through a const reference. Use distinct writable resources for concurrent jobs and separate input and output storage for neighborhood filters.
Buffers and execution
example_pipeline · Transform, clamp and reduce a buffer
Three linked kernels apply an affine transform, clamp its output and compute block sums. This is the shortest complete example of named bindings and shared intermediate storage.
Read the host program · Step-by-step guide
Kernels: affine_kernel, clamp_kernel, sum_kernel.
Look inside the host program
// Resources are linked by binding the same object to adjacent shader ports.
shdr::pipeline pipeline = shdr::dispatch(affine, shdr::extent((count + 63) / 64)) >> // Start with enough 64-wide groups to cover all original inputs.
shdr::dispatch(clip, shdr::extent((count + 31) / 32)) >> // Run the linked clip shader with its own 32-wide workgroup size.
shdr::dispatch(sum, shdr::extent(1)); // Finish with one deterministic reduction invocation over the clipped resource.
run.run(pipeline); // Execute the configured pipeline on the requested backend.
float expected = 0.0f; // Start the independent host reference sum at zero.
const shdr::buffer<float>& read_input = input; // Use a constant buffer view so GPU writes synchronize before host reads.
for (unsigned i = 0; i < count; ++i) // Apply the same scale, offset and clipping formula to every original input.
expected += std::min(8.0f, std::max(0.0f, read_input.data()[i] * 2.0f + 1.0f)); // Accumulate the independent reference from the original inputs.
const shdr::buffer<float>& read_result = result; // Use a constant buffer view so GPU writes synchronize before host reads.
shdr_examples::require_close(read_result.data()[0], expected, "pipeline sum"); // Check the computed value against the independent reference.
std::cout << (run.gpu() ? "GPU" : "CPU") << " buffer pipeline: " << read_result.data()[0] // Write this part of the example result or diagnostic.
<< "\n"; // Write this part of the example result or diagnostic.
example_hybrid · Choose a backend for each stage
Run an explicit CPU clamp between GPU stages. The same buffers carry data across each backend boundary and the runtime synchronizes the required storage.
Read the host program · Step-by-step guide
Kernels: affine_kernel, clamp_kernel, sum_kernel.
example_images · Connect buffers and image storage
Move a scalar buffer into an image, apply a neighborhood blur, then move the image result back into a buffer.
Read the host program · Step-by-step guide
Kernels: buffer_to_image_kernel, blur_kernel, image_to_buffer_kernel.
example_async · Keep several jobs in flight
Use a bounded CPU executor or a three-slot GPU submission ring. Poll completion and reuse each slot only after its earlier job completes.
Read the host program · Step-by-step guide
Kernels: affine_kernel.
Look inside the host program
auto shader = shdr::make_kernel("affine_kernel"); // Create the linked affine kernel instance.
shader->set<unsigned>("count", element_count); // Supply this shader uniform with its typed application value.
shdr::pipeline pipeline(shdr::dispatch(*shader, shdr::extent((element_count + 63) / 64))); // Add a shader dispatch with the required workgroup counts.
std::unique_ptr<shdr::executor> workers; // Declare workers for the following calculation.
if (!runner.gpu()) // Check this condition before entering the following branch.
workers.reset(new shdr::executor(2, slot_count)); // Apply reset to these arguments.
if (runner.gpu()) { // Check this condition before entering the following branch.
// Initial program compilation and every slot's allocation/upload happen
// before entering the polling loop.
for (unsigned index = 0; index < slot_count; ++index) { // Iterate over index for this calculation.
shader->bind("input_values", slots[index].input) // Connect this shader port to its application resource.
.bind("output_values", slots[index].output); // Connect this shader port to its application resource.
pipeline.prepare(*runner.device()); // Apply prepare to these arguments.
} // End this block.
} // End this block.
example_dynamic · Load a shader stage from a module
Create the affine stage through a dynamically loaded plugin and connect it to host-owned clamp and reduction stages. Keep the module loaded until its kernels are destroyed.
Read the host program · Read the plugin · Step-by-step guide
Kernels: affine_kernel, clamp_kernel, sum_kernel.
Imaging and spectral processing
example_imaging · Unpack Bayer data and compress integer streams
Check four Bayer phases across Bayer8, Bayer16, MIPI RAW10 and RAW12 packing, followed by bilinear demosaicing and luminance. A second pipeline counts, offsets, encodes and decodes tiled lossless runs.
Read the host program · Step-by-step guide
Kernels: bayer_unpack_kernel, debayer_kernel, luminance_kernel, rle_count_kernel, rle_offsets_kernel, rle_encode_kernel, rle_decode_kernel.
example_vision · Find corners after smoothing
Run horizontal and vertical Gaussian filters, Sobel gradients, the structure tensor, Harris response and nonmaximum suppression. Independent numerical references check each processing stage and the resulting corner mask.
Read the host program · Step-by-step guide
Kernels: gaussian_horizontal_kernel, gaussian_vertical_kernel, sobel_kernel, harris_tensor_kernel, harris_response_kernel, nonmax_kernel.
Look inside the host program
const shdr::extent groups((count + 63) / 64); // Construct groups with these initial values.
auto pipeline = shdr::dispatch(*gaussian_x, groups) >> // Add a shader dispatch with the required workgroup counts.
shdr::dispatch(*gaussian_y, groups) >> shdr::dispatch(*sobel, groups) >> // Add a shader dispatch with the required workgroup counts.
shdr::dispatch(*tensor, groups) >> shdr::dispatch(*harris, groups) >> // Add a shader dispatch with the required workgroup counts.
shdr::dispatch(*nonmax, groups); // Add a shader dispatch with the required workgroup counts.
run.run(pipeline); // Execute the configured pipeline on the requested backend.
const std::vector<float> expected_blur = gaussian_reference(input, width, height); // Set expected blur from this expression.
const std::vector<glsl::vec2> expected_gradients = // Set expected gradients from this expression.
gradient_reference(expected_blur, width, height); // Apply gradient reference to these arguments.
const std::vector<float> expected_response = // Set expected response from this expression.
harris_reference(expected_gradients, width, height, harris_k); // Apply harris reference to these arguments.
const shdr::buffer<float>& read_blur = blurred; // Use a constant buffer view so GPU writes synchronize before host reads.
const shdr::buffer<glsl::vec2>& read_gradients = gradients; // Use a constant buffer view so GPU writes synchronize before host reads.
example_spectral · Link convolution and a complex 2D transform
Apply dynamic 2D filters, perform a separable forward and inverse direct DFT, and filter a 3D volume along three axes. The small direct transform is educational and is separate from the faster radix-2 signal FFT.
Read the host program · Step-by-step guide
Kernels: convolution2d_kernel, convolution3d_kernel, dft_rows_kernel, dft_columns_kernel.
example_signal · Transform and filter channel-major signals
Use batched forward and inverse radix-2 FFTs, windows and frequency masks. Compare causal FIR modes and persistent biquad streams against independent references.
Read the host program · Step-by-step guide
Kernels: fft_bit_reverse_kernel, fft_butterfly_kernel, signal_window_kernel, signal_frequency_mask_kernel, signal_fir_kernel, signal_biquad_kernel.
Look inside the host program
#include "fft_checks.hpp" // Check FFT, spectral masks, and input windows.
#include "signal_filters_checks.hpp" // Check causal FIR and streaming biquad filters.
int main(int argc, char** argv) { // Run every signal example with the same selected backend.
try { // Report dimension or numerical errors as a failed example.
shdr_examples::runner run(argc, argv); // Use CPU by default or the requested GPU profile.
shdr_examples::check_fft1d(run); // Validate the forward and inverse complex transforms.
shdr_examples::check_frequency_filters(run); // Validate all frequency-domain filter modes.
shdr_examples::check_signal_windows(run); // Validate windowed spectral analysis.
shdr_examples::check_signal_filters( // Validate FIR responses and persistent biquad state.
run); // Validate FIR responses and persistent biquad state.
std::cout << (run.gpu() ? "GPU" : "CPU") // Report the completed real-data processing check.
<< " signal pipelines passed\n"; // Show which backend completed the checks.
return 0; // All processing and reference comparisons succeeded.
#ifdef SHDR_HAVE_EGL // The optional EGL backend can identify unavailable contexts.
} catch (const shdr_examples::context_unavailable& // Select the profiles supplied by the driver.
Events and neural models
example_evt3 · Decode events and estimate normal flow
Preserve EVT3 stream order through block summaries, state seeding, compact offsets and direct output. Append an event-centered timestamp-plane fit while keeping decoded events and their count on the selected backend.
Read the host program · Step-by-step guide
Kernels: evt3_summary_kernel, evt3_seed_kernel, rle_offsets_kernel, evt3_emit_kernel, evt3_reset_kernel, evt3_flow_kernel.
Look inside the host program
reference_decoder reference; // Declare reference for the following calculation.
const std::vector<uvec4> expected = reference.decode(words); // Set expected from this expression.
runner.run(decoder.reset_pipeline()); // Execute the configured pipeline on the requested backend.
compare(decoder, expected, reference); // Apply compare to these arguments.
runner.run(decoder.reset_pipeline()); // Execute the configured pipeline on the requested backend.
compare(decoder, expected, reference); // Apply compare to these arguments.
} // End this block.
shdr_examples::evt3_decoder decoder(6013); // Construct decoder with these initial values.
words = shdr_examples::evt3_random_words(6013, 897); // Set words from this expression.
decoder.load(words); // Apply load to these arguments.
reference_decoder reference; // Declare reference for the following calculation.
const std::vector<uvec4> expected = reference.decode(words); // Set expected from this expression.
runner.run(decoder.reset_pipeline()); // Execute the configured pipeline on the requested backend.
compare(decoder, expected, reference); // Apply compare to these arguments.
} // End this block.
example_neural · Train a small fully connected network
Train all 33 parameters of a two-feature, eight-neuron ReLU network with a sigmoid classifier. Analytic gradients and SGD updates run in the native shader pipeline.
Read the host program · Step-by-step guide
Kernels: ann_infer_kernel, ann_gradient_kernel, nn_sgd_kernel, nn_binary_loss_kernel.
example_cnn · Train a small convolutional network
Train both 3×3 filters and the output classifier in a compact 23-parameter CNN. Separate prediction and update pipelines share the same parameter storage.
Read the host program · Step-by-step guide
Kernels: cnn_infer_kernel, cnn_gradient_kernel, nn_sgd_kernel, nn_binary_loss_kernel.
example_transformer · Train a small attention model
Train all 134 parameters of a four-token, width-four attention model with positional features, RMS normalization, residual feed-forward layers and a two-class head. The example checks analytic derivatives against an independent double-precision oracle.
Read the host program · Step-by-step guide
Kernels: transformer_infer_kernel, transformer_gradient_kernel, nn_sgd_kernel.
Data, validation and measurement
example_real_data · Run the algorithms on public inputs
Evaluate image, waveform, event and digit fixtures. The seven-stage LeNet-style model uses 61,706 trained parameters and compares held-out MNIST labels and independent framework logits. Other cases report backend and oracle checks appropriate to their inputs.
Read the host program · Step-by-step guide
Kernels: lenet_conv_kernel, lenet_pool_kernel, lenet_dense_kernel.
Look inside the host program
shdr::dispatch(*affine, shdr::extent((count + 63u) / 64u)) >> // Dispatch the affine stage with its configured geometry.
shdr::dispatch(*clamp, shdr::extent((count + 31u) / 32u), shdr::backend::cpu) >> // Dispatch the clamp stage with its configured geometry.
shdr::dispatch(*sum, shdr::extent(1)); // Force one stage onto CPU in a mixed pipeline.
data::evaluate( // Compare the complete real-data pipeline outputs on CPU and the requested GPU backend.
run, // Select the same execution backend for this complete case.
"NASA mixed CPU/GPU resources", // Use the exact diagnostic or comparison label for this case.
hybrid, // Validate real-data ownership changes between backends.
{&clipped_check, &total_check}); // Validate real-data ownership changes between backends.
if (run.gpu()) { // Exercise the library's headless asynchronous GPU path.
stages.prepare(*run.device()); // Compile programs and allocate resources before polling.
auto completion = // Queue the GPU work and obtain its completion fence.
stages.submit(*run.device()); // Queue the GPU work and obtain its completion fence.
while (!completion.ready()) { // Poll the completion fence from the context thread.
std::this_thread:: // Allow other application work while processing remains in flight.
yield(); // Allow other application work while processing remains in flight.
example_benchmark · Measure completed CPU and GPU operations
Measure 25 resident operations after preparation and warmup. GPU timings include dispatch completion. The timed interval starts after compilation and initial uploads and ends before final downloads, measuring the completed resident processing workload.
Read the host program · Step-by-step guide
Inspect an embedded GPU program
The export_shader utility exports an embedded GPU program for a chosen factory and profile. Use it to inspect the source passed to the driver or to check that program with a GLSL compiler. Application pipelines use the embedded programs directly.
# Export a registered native shader using the GLES 3.1 profile.
./build/export_shader affine_kernel es31 > affine.comp
# Validate the exported compute shader when glslangValidator is installed.
glslangValidator -S comp affine.comp
Read the exporter, the import and portability guide, and the public-source verification report.
Native kernel catalog
Every source below registers the filename stem followed by _kernel. The shared math kernel is used by the math parity checks. Some shaders are reused by several example applications.
| Native source and factory | Purpose |
|---|---|
| affine_kernel | Apply a scale and offset to a buffer. |
| ann_gradient_kernel | Analytic binary cross-entropy gradients for every row and every ANN parameter. |
| ann_infer_kernel | A fully connected 2 -> ReLU(8) -> sigmoid(1) classifier, one invocation per row. |
| bayer_unpack_kernel | Decode byte-addressed Bayer8, little-endian Bayer16, MIPI RAW10 or MIPI RAW12. |
| blur_kernel | A 3x3 image filter with explicit edge clamping, identical on CPU and GPU. |
| buffer_to_image_kernel | Demonstrate the same resource moving from an SSBO into an r32f image. |
| clamp_kernel | A second stage can use a different workgroup size and share buffer objects. |
| cnn_gradient_kernel | Train convolution coefficients, biases, and the classifier head with analytic gradients. |
| cnn_infer_kernel | 8x8 grayscale -> two valid 3x3 filters -> ReLU -> global mean -> sigmoid classifier. |
| convolution2d_kernel | Two-channel 2D convolution, x/y can also hold a complex sample's real/imaginary |
| convolution3d_kernel | Scalar-volume 3D convolution with dynamic coefficients and clamp-to-edge. |
| debayer_kernel | Bilinear demosaicing of all four Bayer phases, with clamp-to-edge sampling. |
| dft_columns_kernel | The second separable DFT stage transforms columns of a complex vec2 buffer. |
| dft_rows_kernel | Educational direct DFT along each row of a row-major complex vec2 buffer. |
| evt3_emit_kernel | Decode blocks concurrently into disjoint compact output intervals, in input order. |
| evt3_flow_kernel | Estimate normal optical flow by fitting a local plane to event timestamps. |
| evt3_reset_kernel | Reset state inside a pipeline when independent batches or reproducible timings are needed. |
| evt3_seed_kernel | Resolve inter-block dependencies using small summaries, retaining stream state. |
| evt3_summary_kernel | Summarize independent EVT3 blocks. Two 16-bit sensor words share each uint. |
| fft_bit_reverse_kernel | Arrange complex values in the order needed by radix-two butterflies. |
| fft_butterfly_kernel | Apply one radix-two FFT stage with precomputed complex phases. |
| gaussian_horizontal_kernel | First pass of a separable Gaussian approximation: [1,4,6,4,1] / 16. |
| gaussian_vertical_kernel | Second Gaussian pass, its separate output avoids in-place neighborhood races. |
| harris_response_kernel | Smooth the structure tensor with a 3x3 [1,2,1] outer product, then evaluate Harris. |
| harris_tensor_kernel | Encode the symmetric gradient outer product as (dxdx,dxdy,dy*dy,0). |
| image_to_buffer_kernel | End an image pipeline with an SSBO, ready for another stage or host readback. |
| lenet_conv_kernel | Apply a valid convolution with optional zero padding and ReLU. |
| lenet_dense_kernel | Apply a learned dense layer with an optional ReLU activation. |
| lenet_pool_kernel | Downsample independent channel planes with two-by-two average pooling. |
| luminance_kernel | Linear RGB to Rec.709 luminance. Transfer-function decoding belongs upstream. |
| math_kernel | Native GLSL compute source. The build compiles a generated C++11 adapter and |
| nn_binary_loss_kernel | Compute mean binary cross-entropy for a small validation batch. |
| nn_sgd_kernel | Batch-reduce independent parameter gradients and perform an in-place SGD update. |
| nonmax_kernel | Keep positive response peaks, deterministic index ordering breaks equal-value ties. |
| rgba_float_image_kernel | GLES requires separate readonly/writeonly declarations for RGBA images. |
| rgba_int_image_kernel | Signed integer RGBA images use the same two-port pattern on every profile. |
| rgba_uint_image_kernel | Unsigned integer image math uses exact integer-valued image loads and stores. |
| rle_count_kernel | Count compact (value,run length) pairs independently within each fixed-size tile. |
| rle_decode_kernel | Reconstruct each tile from its compact range, preserving every input sample bit. |
| rle_encode_kernel | Lossless tiled RLE: disjoint tile ranges produce one compact global word stream. |
| rle_offsets_kernel | Serial prefix stage for a small tile table, independent encoders use these offsets. |
| scalar_images_kernel | Three image bindings fit even the minimum GLES 3.1 compute image limit. |
| signal_biquad_kernel | Transposed direct-form II biquad, one sequential channel per invocation. |
| signal_fir_kernel | Causal FIR over independent channel-major samples, with zero-prefix batch history. |
| signal_frequency_mask_kernel | Apply a symmetric low-pass, high-pass, band-pass, or band-stop FFT response. |
| signal_window_kernel | Apply a rectangular, Hann, Hamming, or Blackman window before a block FFT. |
| sobel_kernel | Normalized Sobel gradients, stored as (dx,dy) in one std430 vec2 element. |
| sum_kernel | A small deterministic reduction: one invocation reads the preceding stage. |
| transformer_gradient_kernel | Generated by scripts/generate_transformer.py. Edit its shared function body. |
| transformer_infer_kernel | Generated by scripts/generate_transformer.py. Edit its shared function body. |
Browse every file
Read or download the complete applications, shaders, reusable pipeline wrappers and runtime header in the source browser.