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.

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.